Reputation: 841
I have a following type newtype Arr2 e1 e2 a = Arr2 { getArr2 :: e1 -> e2 -> a }
.
And I got to write Functor instance for it, yet i don't really understand how
I tried
instance Functor (Arr2 e1 e2) where
fmap g (Arr2 a) = Arr2 (g a)
and
instance Functor (Arr2 e1 e2) where
fmap g = g . getArr2
which actually results in type
(a -> b) -> Arr2 e1 e2 a -> b
instead of desired
(a -> b) -> Arr2 e1 e2 a -> Arr2 e1 e2 b
So please, help me
Upvotes: 5
Views: 9170
Reputation: 1365
The answer provided by Willem Van Onsem is very good, I would just like to suggest the use of a language extension that can easily create Functor
instances for newtypes: DeriveFunctor
.
At the top of your module you can add:
{-# LANGUAGE DeriveFunctor #-}
Then you can automatically derive your Functor
instance:
newtype Arr2 e1 e2 a = Arr2 { getArr2 :: e1 -> e2 -> a } deriving Functor
Here's is how I would find out the type of fmap
for this instance in GHCi:
λ > :set -XDeriveFunctor
λ > newtype Arr2 e1 e2 a = Arr2 { getArr2 :: e1 -> e2 -> a } deriving Functor
λ > :set -XTypeApplications
λ > :t fmap @(Arr2 _ _)
fmap @(Arr2 _ _) :: (a -> b) -> Arr2 t t1 a -> Arr2 t t1 b
Upvotes: 3
Reputation: 476624
The Functor
class has as definition:
class Functor f where:
fmap :: (a -> b) -> f a -> f b
(<$) :: a -> f b -> f a
The (<$)
has a default implementation: (<$) = fmap . const
which works fine.
So that means that if we enter a function (g :: a -> b
) as first argument, and an Arr2
that produces an a
, we have to generate an Arr2
that calls that g
on the outcome of the arrow if it is applied.
As a result the definition of fmap
for your Arr2
is:
instance Functor (Arr2 e1 e2) where
fmap g (Arr2 a) = Arr2 (\x y -> g (a x y))
Or more elegantly:
instance Functor (Arr2 e1 e2) where
fmap g (Arr2 a) = Arr2 (\x -> g . (a x))
Or a more elegant version - commented by @Alec:
instance Functor (Arr2 e1 e2) where
fmap g (Arr2 a) = Arr2 ((g .) . a)
(you can convert expressions to pointfree ones using this tool)
Upvotes: 6