This is a self-motivated exercise. To get the final case of <*>
to work, I resorted to implementing concatenation
as an auxiliary function. Have I missed a trick? That is, could that case have been written without needing an auxiliary function or be written in some other way? (BTW, my principle reference is the Haskell Wikibook, if that's relevant.)
The code:
data List a = Empty | Item a (List a)
deriving (Eq, Ord, Show, Read)
instance Functor List where
fmap ab Empty = Empty
fmap ab (Item a la) = Item (ab a) (fmap ab la)
instance Applicative List where
pure a = Item a Empty
Empty <*> _ = Empty
_ <*> Empty = Empty
Item ab lab <*> Item a la = -- this is the case in question
Item (ab a) (concatenation (ab <$> la) (lab <*> Item a la))
I guess what it comes down to is that, as far as I can recall in my limited experience, I've not needed an auxiliary function to implement any kind of instance so using one here makes me wonder whether it's necessary ...
There's no reason to avoid auxiliary functions. However you define the instance, it either needs to use concatenation
, or reimplement parts or all of its definition.