我一直在尝试出色的Programming in Haskell (2nd ed)。不过,我对Applicatives的问题有点困惑。
给出以下类型:
data Expr a = Var a | Val Int | Add (Expr a) (Expr a) deriving Show
问题是编写Functor
,Applicative
和Monad
类的实现。
Functor
很简单,Monad
也很简单(至少它可以编译,我还没有完全将其包裹住,但是我更担心这一点)。
我已经提出了这个问题,可以编译,但是我有担心:
instance Applicative Expr where
-- pure :: a -> Expr a
pure = Var
-- (<*>) :: Expr (a -> b) -> Expr a -> Expr b
(Var fab) <*> fa = fmap fab fa
pure
很好,但是我担心实际的应用运算符<*>
。据我所知,它仅对Var
有意义,而对Val
或Add
没有意义。对我来说,似乎有点奇怪,您可以表达某种可能爆炸的东西是合法的-例如,您可能拥有Add (Var ord) (Val 10)
类型的Expr (Char -> Int)
,因此将typecheck用作<*>
表达式中的lhs会爆炸,但是(按目前的样子)会爆炸。而且我还不清楚递归定义的工作方式-因为一旦您按下(Val 10)
,您就被塞满了-无法将rhs转换为必要的类型。
我在这里想念什么?如何完成<*>
的定义,以使事情不会爆炸,并且仍然是有效的应用程序?我是否真的想/感觉到您实际上不会设计这样的类型?
谢谢!
答案 0 :(得分:3)
Val :: Int -> Expr a
for any a
. So
Val x <*> _ = Val x
is valid, as is
_ <*> Val y = Val y
as is
Val x <*> Val y = Val (something about x and y)
so unfortunately now you have a choice, which means you are about to make the wrong one. Fortunately only one of these is compatible with the Monad
instance (which one?).
As for the recursive case, you have
Add e e' <*> fb = ...
-- e :: Expr (a -> b)
-- e' :: Expr (a -> b)
-- fb :: Expr a
And you should use all the incoming information to make an Expr b
, as well as preserving the "structure" (Add
). What are all the ways you could make an Expr b
from this (remember you can use the applicative operator recursively)?