了解“在Haskell中编程”的第12章中的应用问题(#7)

时间:2019-01-18 17:50:40

标签: haskell functional-programming applicative

我一直在尝试出色的Programming in Haskell (2nd ed)。不过,我对Applicatives的问题有点困惑。

给出以下类型:

data Expr a = Var a | Val Int | Add (Expr a) (Expr a) deriving Show

问题是编写FunctorApplicativeMonad类的实现。

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有意义,而对ValAdd没有意义。对我来说,似乎有点奇怪,您可以表达某种可能爆炸的东西是合法的-例如,您可能拥有Add (Var ord) (Val 10)类型的Expr (Char -> Int),因此将typecheck用作<*>表达式中的lhs会爆炸,但是(按目前的样子)会爆炸。而且我还不清楚递归定义的工作方式-因为一旦您按下(Val 10),您就被塞满了-无法将rhs转换为必要的类型。

我在这里想念什么?如何完成<*>的定义,以使事情不会爆炸,并且仍然是有效的应用程序?我是否真的想/感觉到您实际上不会设计这样的类型?

谢谢!

1 个答案:

答案 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)?