Monad
can pass Just [1,2]
, which is a different type from what the original length
function takes, to >>= return . length
.
Just [1,2] >>= return . length
Can I say that Monad
makes it possible to see Maybe [a]
as isomorphic with [a]
on length using (>>=, return)
? (Of course they are not really isomorphic.)
Can I choose the term "isomorphic" this situation?
CodePudding user response:
What your example ultimately illustrates is that Maybe
is a functor: if you have some f :: a -> b
, you can use fmap
to turn it into fmap f :: Maybe a -> Maybe b
in a way that preserves identities and composition. Monads are functors, with \f m -> m >>= return . f
being the same as fmap f m
. In your case, we have the length
function being transformed by the Maybe
functor.
can I choose term "isomorphic" this situation?
Not really. fmap
for Maybe
is not an isomorphism. An isomorphism requires there being a two-sided inverse that undoes it, which in this case would be something like:
unFmapMaybe :: (Maybe a -> Maybe b) -> (a -> b)
-- For it to be a two-sided inverse to `fmap`, we should have:
unFmapMaybe . fmap = id
fmap . unFmapMaybe = id
However, there are no (Maybe a -> Maybe b) -> (a -> b)
functions, as there is no way to obtain a b
result if the input Maybe a -> Maybe b
function gives out a Nothing
. While there are specific functors whose fmap
is an isomorphism (Identity
is one example), that is not the case in general.
CodePudding user response:
[a]
is isomorphic to the quotient type of Maybe [a]
with Nothing
and Just []
considered equivalent. Alternatively it is isomorphic to Maybe (NonEmpty a)
, which simply eliminates the Just []
case.
In other words, [a]
can be factorized as a composition of the Maybe
and NonEmpty
functors.
A result of this is that you can lift any function on NonEmpty a
to a function on [a]
:
liftEmptyable :: (NonEmpty a -> r) -> [a] -> Maybe r
liftEmptyable _ [] = Nothing
liftEmptyable f (x:xs) = Just $ f (x:|xs)
Not sure that actually has much to do with your question though. As duplode answered, you don't really do anything but a simple functor mapping. We could at most elaborate that the monad laws ensure that the fmap
really behaves as if length
acted directly on the contained list:
Just [1,2] >>= return . length
≡ return [1,2] >>= return . length -- def. of `Monad Maybe`
≡ return (length [1,2]) -- left-identity monad law