Let's say I have the following newtype
:
newtype Foo = Foo Integer deriving (Eq, Show)
Is there a concise way to add two Foo
's:
(Foo 10) + (Foo 5) == Foo 15
or get the max:
max (Foo 10) (Foo 5) == Foo 5
?
I'm curious if it's possible to easily use functions of a
for a newtype a
rather than do:
addFoo :: Foo -> Foo -> Foo
addFoo (Foo x) (Foo y) = Foo $ x + y
Just as haskell98 knows how to derive those Eq
and Show
instances for you, you can turn on the GeneralizedNewtypeDeriving
extension to ghc to get the Num
and Ord
instances you need:
Prelude> :set -XGeneralizedNewtypeDeriving
Prelude> newtype Foo = Foo Integer deriving (Eq, Show, Num, Ord)
Prelude> (Foo 10) + (Foo 5) == Foo 15
True
Prelude> max (Foo 10) (Foo 5) == Foo 5
False
You want to lift functions of the type Integer -> Integer -> Integer
to Foo -> Foo -> Foo
. To do so you could define utility functions:
liftFoo :: (Integer -> Integer) -> Foo -> Foo
liftFoo f (Foo a) = Foo $ f a
liftFoo2 :: (Integer -> Integer -> Integer) -> Foo -> Foo -> Foo
liftFoo2 f (Foo a) (Foo b) = Foo $ f a b
-- and so on
Then you could use it as follows:
liftFoo2 (+) (Foo 10) (Foo 5)
liftFoo2 max (Foo 10) (Foo 5)
This has the advantage of not requiring an extension.
Another option is to make the definition of the Foo
newtype more permissible so that you could make it an instance of Functor
and Applicative
:
import Control.Applicative
newtype Foo a = Foo a deriving (Eq, Show)
foo :: Integer -> Foo Integer
foo = Foo
instance Functor Foo where
fmap f (Foo a) = Foo $ f a
instance Applicative Foo where
pure = Foo
(Foo f) <*> (Foo a) = Foo $ f a
Now you could do the following:
(+) <$> foo 10 <*> foo 5
max <$> foo 10 <*> foo 5
Because foo
is specialized to the Integer
type you don't lose any benefits of type checking.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With