Last active
April 3, 2023 17:01
-
-
Save Profpatsch/b49c5f4bace41fa07338e8c07252d712 to your computer and use it in GitHub Desktop.
Implement only `fromInteger` for types where num-literals are possible, with less boilerplate
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- | Implement this class if you want your type to only implement the part of 'Num' | |
-- that allows creating them from Integer-literals, then derive Num via 'NumLiteralOnly': | |
-- | |
-- @ | |
-- data Foo = Foo Integer | |
-- deriving (Num) via (NumLiteralOnly "Foo" Foo) | |
-- | |
-- instance IntegerLiteral Foo where | |
-- integerLiteral i = Foo i | |
-- @ | |
class IntegerLiteral a where | |
integerLiteral :: Integer -> a | |
-- | The same as 'IntegerLiteral' but for floating point literals. | |
class RationalLiteral a where | |
rationalLiteral :: Rational -> a | |
-- | Helper class for @deriving (Num) via …@, implements only literal syntax for integer and floating point numbers, | |
-- and throws descriptive runtime errors for any other methods in 'Num'. | |
-- | |
-- See 'IntegerLiteral' and 'RationalLiteral' for examples. | |
newtype NumLiteralOnly (sym :: Symbol) num = NumLiteralOnly num | |
instance (IntegerLiteral num, KnownSymbol sym) => Num (NumLiteralOnly sym num) where | |
fromInteger = NumLiteralOnly . integerLiteral | |
(+) = error [fmt|Only use as numeric literal allowed for {symbolVal (Proxy @sym)}, you tried to add (+) (NumLiteralOnly)|] | |
(*) = error [fmt|Only use as numeric literal allowed for {symbolVal (Proxy @sym)}, you tried to multiply (*) (NumLiteralOnly)|] | |
(-) = error [fmt|Only use as numeric literal allowed for {symbolVal (Proxy @sym)}, you tried to subtract (-) (NumLiteralOnly)|] | |
abs = error [fmt|Only use as numeric literal allowed for {symbolVal (Proxy @sym)}, you tried to use `abs` (NumLiteralOnly)|] | |
signum = error [fmt|Only use as numeric literal allowed for {symbolVal (Proxy @sym)}, you tried to use `signum` (NumLiteralOnly)|] | |
instance (IntegerLiteral num, RationalLiteral num, KnownSymbol sym) => Fractional (NumLiteralOnly sym num) where | |
fromRational = NumLiteralOnly . rationalLiteral | |
recip = error [fmt|Only use as rational literal allowed for {symbolVal (Proxy @sym)}, you tried to use `recip` (NumLiteralOnly)|] | |
(/) = error [fmt|Only use as numeric literal allowed for {symbolVal (Proxy @sym)}, you tried to divide (/) (NumLiteralOnly)|] | |
as numeric literal allowed for {symbolVal (Proxy @sym)}, you tried to use `signum` (NumLiteralOnly)|] | |
data Foo = Foo Integer | |
deriving (Num) via (NumLiteralOnly "Foo" Foo) | |
instance IntegerLiteral Foo where | |
integerLiteral i = Foo i |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment