理解“第12章”中的应用问题(“7”);在Haskell中编程;
我一直在努力完成这项出色的工作。不过,关于应用程序的问题让我有点困惑 鉴于以下类型:理解“第12章”中的应用问题(“7”);在Haskell中编程;,haskell,functional-programming,applicative,Haskell,Functional Programming,Applicative,我一直在努力完成这项出色的工作。不过,关于应用程序的问题让我有点困惑 鉴于以下类型: data Expr a = Var a | Val Int | Add (Expr a) (Expr a) deriving Show 问题是编写Functor、Applicative和Monad类的实现 Functor很简单,就像Monad一样(至少它可以编译,我还没有完全理解它,但首先我更担心这一点) 我已经提出了这个,可以编译,但我有一些担心: instance Applicative Expr whe
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
实例应用程序表达式,其中
--纯::a->Expr a
纯=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转换成必要的类型
我错过了什么?如何完成
的定义,使事情不会爆炸,并且它仍然是一个有效的应用程序?我的想法/感觉是对的,在现实中,你不会设计这样的类型吗
谢谢
Val :: Int -> Expr a
对于任何a
。所以
Val x <*> _ = Val x
您应该使用所有传入的信息生成一个
Expr b
,并保留“结构”(Add
)。您可以通过哪些方法从中生成Expr b
(请记住,您可以递归使用applicative操作符)?如果您已经有Monad
实例,您只需定义()=ap
(从Control.Monad
)。您可以展开定义ap fab fa
,了解其工作原理。事实上,在这种情况下,定义fmap
、return
和join
非常简单直观。然后可以用来构建单子。相比之下,定义应用程序实例感觉就不那么自然了:我只是按照luqui的建议使用()=ap
,然后忘记它:-p我会学习所有这些东西,所以我只做了bind
/=
-我只是模糊地意识到ap
和join
,还没有真正了解它们。我记得有些东西你们可以用其他的东西来定义,反之亦然。希望这本书能更深入地了解它,在完成这本书之后,通过Typeclassopdia将有助于连接这些点。而且,你知道,写一些实际的代码:)尽管,valxvaly=…
不是真正的选择,是吗?那么Val x(Add l r)
和Val x Var r
呢?正如你所建议的,只有一个正确的答案,正如你在其他地方建议的那样,通过使用ap
很容易验证。回答得很好,谢谢你帮助我建立我的直觉和理解,而不只是简单地说“这样做”。真的很感激!
_ <*> Val y = Val y
Val x <*> Val y = Val (something about x and y)
Add e e' <*> fb = ...
-- e :: Expr (a -> b)
-- e' :: Expr (a -> b)
-- fb :: Expr a