This answer is complementary to the ones already given, and focusses only on a part of the question:
As far as I understand, it should be possible to implement <*>
for lists only using fmap
, as it is the case with applicative Maybe. How?
You seem to refer to this implementation:
instance Applicative Maybe where
pure = Just
Nothing <*> _ = Nothing
(Just f) <*> something = fmap f something
Well, yes, we can do that for lists as well - using nothing but fmap
, pattern matching and constructors:
instance Applicative [] where
pure = []
[] <*> _ = []
(f:fs) <*> something = fmap f something ++ (fs <*> something)
where
[] ++ yy = ys
(x:xs) ++ ys = x : (xs++ys)
Admittedly, this does require some kind of concatenation, as lists are a more complex type than Maybes. There are other possible applicative instances for lists that would require less code than this "everything-with-everything" behaviour, but those are not compatible to the default monad instance (which is the common expectation).
Of course, monad notation does simplify this dramatically:
instance Monad m => Applicative m where
pure = return
mf <*> something = mf >>= (\f -> fmap f something) -- shorter: (`fmap` something)
…which works for both Maybe
and []
as m
.