[我正在阅读有关Haskell的Graham Hutton的书,并且不要一口气地进行一项练习。练习内容如下:
给出以下类型表达式
data Expr a = Var a | Val Int | Add (Expr a) (Expr a) deriving Show
其中包含某种类型a的变量,展示了如何使这种类型成为Functor,Applicative和Monad类的实例。借助示例,解释此类型的>>=
运算符的作用。
我在定义Applicative的<*>
运算符时遇到了问题。 <*>
的类型是:
(<*>) :: Expr (a -> b) -> Expr a -> Expr b
我不知道(Val n) <*> mx
的工作原理,因为从理论上讲我需要提供Expr b
,但我所拥有的只是Expr a
,并且没有转换(a -> b
)的函数。
我也不明白在(Add l r) <*> mx
情况下该怎么办。
这是我的实现。
instance Functor Expr where
--fmap :: (a -> b) -> Expr a -> Expr b
fmap g (Var x) = Var (g x)
fmap g (Val n) = Val n
fmap g (Add l r) = Add (fmap g l) (fmap g r)
instance Applicative Expr where
--pure :: a -> Expr a
pure = Var
-- <*> :: Expr (a -> b) -> Expr a -> Expr b
(Var g) <*> mx = fmap g mx
--(Val n) <*> mx = ???
--(Add l r) <*> mx = ???
instance Monad Expr where
-- (>>=) :: Expr a -> (a -> Expr b) -> Expr b
(Var x) >>= g = g x
(Val n) >>= g = Val n
(Add l r) >>= g = Add (l >>= g) (r >>= g)
expr = Add (Add (Var 'a') (Val 4)) (Var 'b')
最后,我对monad中的>> =有疑问。这个运算符的想法是做诸如替换变量之类的事情?喜欢:
expr >>= (\x -> if x == 'a' then Val 6 else Var x) >>= (\x -> if x == 'b' then Val 7 else Var x)
[定义了pure
和(>>=)
后,(<*>)
的一种可能的定义是
(<*>) = Control.Monad.ap
其中ap
在标准库中定义为
ap :: Monad m => m (a -> b) -> m a -> m b
ap mf mx = do
f <- mf
x <- mx
pure (f x)
实际上,(<*>)
的任何定义都必须与存在Monad
实例的情况相同。