-- | Convert a 'Maybe a' to an equivalent 'Either () a'. Should be inverse
-- to 'eitherUnitToMaybe'.
maybeToEitherUnit :: Maybe a -> Either () a
maybeToEitherUnit a = error "Not yet implemented: maybeToEitherUnit"
-- | Convert a 'Either () a' to an equivalent 'Maybe a'. Should be inverse
-- to 'maybeToEitherUnit'.
eitherUnitToMaybe :: Either () a -> Maybe a
eitherUnitToMaybe = error "Not yet implemented: eitherUnitToMaybe"
-- | Convert a pair of a 'Bool' and an 'a' to 'Either a a'. Should be inverse
-- to 'eitherToPairWithBool'.
pairWithBoolToEither :: (Bool,a) -> Either a a
pairWithBoolToEither = undefined -- What should I do here?
-- | Convert an 'Either a a' to a pair of a 'Bool' and an 'a'. Should be inverse
-- to 'pairWithBoolToEither'.
eitherToPairWithBool :: Either a a -> (Bool,a)
eitherToPairWithBool = undefined -- What should I do here?
-- | Convert a function from 'Bool' to 'a' to a pair of 'a's. Should be inverse
-- to 'pairToFunctionFromBool'.
functionFromBoolToPair :: (Bool -> a) -> (a,a)
functionFromBoolToPair = error "Not yet implemented: functionFromBoolToPair"
-- | Convert a pair of 'a's to a function from 'Bool' to 'a'. Should be inverse
-- to 'functionFromBoolToPair'.
pairToFunctionFromBool :: (a,a) -> (Bool -> a)
pairToFunctionFromBool = error "Not yet implemented: pairToFunctionFromBool"
I don't really know what to do. I know what maybe is, but I think I have a problem with either, because Either a a
makes no sense in my mind. Either a b
would be okay. This is either a or b but Either a a
is a
?!
I don't have any idea in general how to write these functions.
Note that
Either a b
means quite literally that a value of such a type can be either ana
, or ana
. It sounds like you have actually grasped this concept, but the piece you're missing is that theEither
type differentiates between values constructed withLeft
and those constructed withRight
.For the first part, the idea is that
Maybe
is eitherJust
a thing orNothing
--Nothing
corresponds to()
because both are "in essence" data types with only one possible value.The idea behind converting
(Bool, a)
pairs toEither a a
pairs might seem a little trickier, but just think about the correspondence betweenTrue
andFalse
andLeft
andRight
.As for converting functions of type
(Bool -> a)
to(a, a)
pairs, here's a hint: Consider the fact thatBool
can only have two types, and write down what that initial function argument might look like.Hopefully those hints help you to get started.
Yes it does. Try to figure out the difference between type
a
andEither a a
.Either
is a disjoint union. Once you understand the difference betweena
andEither a a
, your homework should be easy in conjunction with AndrewC's answer.Given that I think this is homework, I'll not answer, but give important hints:
If you look for the definitions on hoogle (http://www.haskell.org/hoogle/) you find
This means that
Bool
can only beTrue
orFalse
, but thatEither a b
can beLeft a
orRight b
.which means your functions should look like
and
Comparing with
Maybe
Maybe a
is given byso something of type
Maybe Int
could beJust 7
orNothing
.Similarly, something of type
Either Int Char
could beLeft 5
orRight 'c'
.Something of type
Either Int Int
could beLeft 7
orRight 4
.So something with type
Either Int Char
is either anInt
or aChar
, but something of typeEither Int Int
is either anInt
or anInt
. You don't get to choose anything other thanInt
, but you'll know whether it was aLeft
or aRight
.Why you've been asked this/thinking behind it
If you have something of type
Either a a
, then the data (eg5
inLeft 5
) is always of typea
, and you've just tagged it withLeft
orRight
. If you have something of type(Bool,a)
thea
-data (eg5
in(True,5)
) is always the same type, and you've paired it withFalse
orTrue
.The maths word for two things which perhaps look different but actually have the same content is "isomorphic". Your instructor has asked you to write a pair of functions which show this isomorphism. Your answer will go down better if
pairWithBoolToEither . eitherToPairWithBool
andeitherToPairWithBool . pairWithBoolToEither
do whatid
does, i.e. don't change anything. In fact, I've just spotted the comments in your question, where it says they should be inverses. In your write-up, you should show this by doing tests in ghci likeand the other way round.
(In case you haven't seen it,
$
is defined byf $ x = f x
but$
has really low precedence (infixr 0 $
), sof . g $ x
is(f . g) $ x
which is just(f . g) x
and.
is function composition, so(f.g) x = f (g x)
. That was a lot of explanation to save one pair of brackets!)Functions that take or return functions
This can be a bit mind blowing at first when you're not used to it.
The only thing you can pattern match a function with is just a variable like
f
, so we'll need to do something likebut what can we do with that
f
? Well, the easiest thing to do with a function you're given is to apply it to a value. What value(s) can we usef
on? Wellf :: (Bool -> a)
so it takes aBool
and gives you ana
, so we can either dof True
orf False
, and they'll give us two (probably different) values of typea
. Now that's handy, because we needed toa
values, didn't we?Next have a look at
The pattern match we can do for the type
(a,a)
is something like(x,y)
so we'll needbut how can we return a function
(Bool -> a)
on the right hand side?There are two ways I think you'll find easiest. One is to notice that since
->
is right associative anyway, the type(a,a) -> (Bool -> a)
is the same as(a,a) -> Bool -> a
so we can actually move the arguments for the function we want to return to before the = sign, like this:Another way, which feels perhaps a little easier, would to make a
let
orwhere
clause to define a function called something likef
, wheref :: Bool -> a
< a bit like:Have fun. Mess around.
Perhaps it's useful to note that
Either a b
is also called the coproduct, or sum, of the typesa
andb
. Indeed it is now common to useYou can then write
Either a b
asa + b
.Now common sense would dictate that we rewrite
a + a
as something like2 ⋅ a
. Believe it or not, that is exactly the meaning of the tuple type you're transforming to!To explain: algebraic data types can roughly be seen as "counting1 the number of possible constructions". So
has two constructors. So sort of (this is not valid Haskell!)
Tuples allow all the combinations of constructors from each argument. So for instance in
(Bool, Bool)
, we have the valuesYou've guessed it: tuples are also called products. So the type
(Bool, a)
is basically2 ⋅ a
: for every valuex :: a
, we can create both the(False, x)
tuple and the(True, x)
tuple, alltogether twice as many as there arex
values.Much the same thing for
Either a a
: we always have bothLeft x
andRight x
as a possible value.All your functions with "arithmetic types":
1For pretty much any interesting type there are actually infinitely many possible values, still this kind of naïve arithmetic gets you surprisingly far.