Reputation: 57
I'm new to Haskell, learning Functor, Applicative, and Monad.
I checked the Functor instance for Either
type from hackage is:
data Either a b = Left a | Right b
instance Functor (Either a) where
fmap _ (Left x) = Left x
fmap f (Right y) = Right (f y)
and I am asked to do the Functor, Applicative, Monad instance for extended Either
called MyEither
:
data MyEither a b = MyLeft a | MyRight b | Nothing
deriving (Eq, Show)
My question is:
1 How to extend Nothing
in my instance?
2 Does deriving have to be written in the instance?
Can anyone get me some tips?
Upvotes: 0
Views: 106
Reputation: 71119
When you write down your instances, start by writing out the types explicitly:
data MyEither a b = MyLeft a | MyRight b | MyNothing
deriving (Eq, Show)
instance Functor (MyEither a) where
-- fmap :: Functor f => (b -> c) -> f b -> f c
-- fmap :: (b -> c) -> MyEither a b -> MyEither a c
(I'll use MyNothing
here to prevent any mix-ups with the Maybe
's Nothing
).
And now we are ready to enumerate all possibilities according to the data type definition:
fmap bc (MyLeft aValue) = result where
-- bc :: b -> c
-- MyLeft aValue :: MyEither a b
-- result :: MyEither a c
.....
here we must produce a value of type MyEither a c
as the result. The function bc
is useless here, as we only have access to the value aValue :: a
of type a
:
MyLeft aValue :: MyEither a b
--------------------------------
aValue :: a
Thus we have two possibilities here:
result = MyLeft aValue
which will construct a new value, this time of type MyEither a c
as determined by the type signature; orresult = ...
.Fill the dots, and make the choice between 1. and 2, completing the definition of this clause, fmap bc (MyLeft aValue) = ...
. (but see an important note at the bottom of this post)
The next possibility is
fmap bc (MyRight bValue) = ...
This time we do have an access to a value of type b
, so the function bc
can come quite handy, since
bValue :: b
bc :: b -> c
-------------------------
bc bValue :: c
and
cValue :: c
--------------------------------
myRight cValue :: MyEither a c
Thus the natural definition for this clause is
fmap bc (MyRight bValue) = MyRight cValue
where
cValue = ....
although of course the same second option is also technically possible as was in the first clause.(again, see an important note at the bottom of this post) What's certainly impossible is to use MyLeft
to construct a MyEither a c
value here, as we have absolutely no access to any a
type value at all here.... except undefined
.
And now there's only one more possibility left, for a value of type MyEither a b
that our fmap
must handle, according to its type signature (remember, fmap :: (b -> c) -> MyEither a b -> MyEither a c
). And that value is ...
fmap bc MyNothing =
Again, we must produce a value of type MyEither a c
as the result. This time we have no access to any value of type neither b
nor a
. So there is no other choice other than return ...
.......
(sans the uses of undefined
of course). Do complete the definition.
And I hope you are now able to finish up the other definitions as needed.
Important update: those choices mentioned above are actually no choices at all. Those possibilities do exist if all we're concerned with is making a definition that fits the type. But, the Functor etc instance must also be lawful. Functor laws for example are
fmap id === id
fmap (f . g) === fmap f . fmap g
and in each case only one possibility won't break the laws. In particular, fmap id (MyLeft _) = MyNothing
breaks the first Functor law.
Upvotes: 1
Reputation: 6828
When you implement the instance you don't need to write deriving
. deriving
is for when you let the compiler derive an instance for you when you are defining a new type.
For Nothing
, pattern match on it and return Nothing
for the implementation of all of FAM
. There isn't much you can do with it.
Here is a similar example that may help you.
data Nope a = NopeDataJpg deriving (Eq, Show)
instance Functor Nope where
fmap _ _ = NopeDataJpg
instance Applicative Nope where
pure x = NopeDataJpg
_ <*> _ = NopeDataJpg
instance Monad Nope where
return = pure
_ >>= _ = NopeDataJpg
Also, here are the Functor
, Applicative
, and Monad
implementations of Maybe
in GHC. How they handle Nothing
is pretty similar to what you need to do for your data type.
Upvotes: 3