I've been working through the excellent Programming in Haskell (2nd ed). I'm a bit flummoxed by the question on Applicatives, though.
Given the following type:
data Expr a = Var a | Val Int | Add (Expr a) (Expr a) deriving Show
The question is to write the implementations of the Functor
, Applicative
and Monad
classes.
Functor
is straightforward, as is Monad
(at least it compiles, I've not fully wrapped my head around it yet but I'm more worried about this bit first).
I've come up with this, which compiles, but I have concerns:
instance Applicative Expr where
-- pure :: a -> Expr a
pure = Var
-- (<*>) :: Expr (a -> b) -> Expr a -> Expr b
(Var fab) <*> fa = fmap fab fa
pure
is fine, but I'm worried about the actual applicative operator <*>
. As far as I can tell, it only makes sense for Var
- not for Val
or Add
. And it just seems weird to me that you'd have a type where's it's legal to express things that can explode - for instance, you could have Add (Var ord) (Val 10)
which is of type Expr (Char -> Int)
, so would typecheck as the lhs in a <*>
expression, but (as it stands) would explode. And it's not clear to me how the recursive definition would work - because as soon as you hit (Val 10)
, you're stuffed - there's no way to convert the rhs to the necessary type.
What am I missing here? How do I complete the definition of <*>
such that things don't explode, and it's still a valid applicative? Am I right in thinking/feeling that in reality, you wouldn't design a type like this?
Thanks!