Haskell 如何为以下数据类型定义monad实例?

Haskell 如何为以下数据类型定义monad实例?,haskell,expression,monads,environment,applicative,Haskell,Expression,Monads,Environment,Applicative,以下是我必须使用的代码: infixl 9 :@: -- This is newly defined symbol used in the application of expressions data Expr = Lit Integer -- a literal | Var String -- a variable | Bin Expr Op Expr -- binary operator | Abs String Expr -- a lam

以下是我必须使用的代码:

infixl 9 :@: -- This is newly defined symbol used in the application of expressions

data Expr
  =  Lit Integer      -- a literal
  |  Var String       -- a variable
  |  Bin Expr Op Expr -- binary operator
  |  Abs String Expr  -- a lambda expression
  |  Expr :@: Expr    -- an application
  deriving Show

data Op = Plus | Mult
  deriving Show

data Value = IntVal Integer | FunVal Env String Expr
  deriving Show

type Env = [(String,Value)]

applyIntOp :: Op -> Value -> Value -> Value
applyIntOp op (IntVal v1) (IntVal v2) = 
   case op of 
      Plus -> IntVal (v1 + v2)
      Mult -> IntVal (v1 * v2)

eval :: Expr -> Env -> Value
eval (Lit i)        env = IntVal i
eval (Var v)        env = fromJust (lookup v env)
eval (Bin e1 op e2) env = applyIntOp op (eval e1 env) (eval e2 env)
eval (Abs v b)      env = FunVal env v b
eval (ef :@: ea)    env = let FunVal env var body = eval ef env
                              arg                 = eval ea env
                           in eval body ((var,arg):env) 

目标是生成一个求值函数,以便它可以使用变量(Var字符串),其中的变量来自环境(Env)。但是,当我试图用这些类型中的任何一种来定义monad时,我都不能,因为它们没有正确的类型(*而不是*->*)

那么,我将如何定义这个单子,以便能够使用它正确地计算任何表达式呢

instance Monad ? where
  return = ..
  >>=    = .. 
例如(3+(x*4)(适用)(x=1+2)):


这将返回15个作为旁注,您的
eval(ef:@:ae)
案例是错误的,因为您在评估
ef
ea
时使用了错误的
env
。您希望这样做:

eval (ef :@: ea)    env = let FunVal env' var body = eval ef env
                              arg                  = eval ea env
                           in eval body ((var,arg):env')
不管怎样,让我们先讨论一下像
eval
这样的求值函数“使用monad”的常用方法

您的
eval
函数具有签名:

eval :: Expr -> Env -> Value
即使它的主要目的是获取一个
Expr
并确定它的
值(即,它基本上是一个函数
Expr->Value
),您仍然需要携带一些额外的信息,即描述变量绑定的
Env
。即使您仅在处理
Var
Sub
构造函数时访问这些绑定,并且仅在处理
构造函数时修改这些绑定:@:
构造函数,对于所有不关心它的情况,您仍然需要传递
Env
,尤其是以下情况:

eval (Bin e1 op e2) env = applyIntOp op (eval e1 env) (eval e2 env)
它甚至不触及
env
,但需要将其传递给每个递归
eval
调用

为了避免这种情况,人们通常会引入一元上下文来进行评估。这并不涉及为
Expr
Env
Value
编写monad实例。相反,它涉及将
eval
的签名更改为获取
Expr
并返回
值,但在“一元上下文”中,可使
Env
可供检查和修改:

evalM :: Expr -> MyMonad Value
实际上有一个现成的单子,所以你不必自己写:

import Control.Monad.Reader
type MyMonad = Reader Env
在此之后,编写不关心
Env
的案例就更容易了:

evalM (Lit i) = pure $ IntVal i
evalM (Bin e1 op e2) = applyIntOp op <*> eval e1 <*> eval e2
诚然,在本例中引入
MyMonad
并没有多大帮助,但如果您决定扩展您的语言以支持可变值、错误处理和IO副作用,您将开始看到这种方法的更多优势

同样,这是使用单子进行评估的常用方法,但我不确定这是否是您要问的问题

使用monad进行计算的一种不同寻常的方法是为
Expr
类型编写monad实例,其中monad动作是某种“替换”。真的很难想象这是怎么回事。最明显的出发点是考虑单元格经常被用来递归地替换结构的元素而不改变整体结构的方式。例如,可以将列表单子视为用新列表替换列表中的每个元素,但它不是返回列表列表,而是将所有列表连接在一起,使其具有与原始列表相同的类型。对于叶子上有值的树,通常有一个单子,用一个关联的树替换每个叶子,但不是给出一棵树,而是将结构展平,因此它只是一棵与原始树类型相同的树

从这一点出发,很容易想象用单子替换表达式,其中叶子是变量引用:

data ExprM a
  =  LitM Integer
  |  VarM a
  |  BinM (ExprM a) Op (ExprM a)
  deriving (Show, Functor)
一元操作可以是将每个
VarM a
(叶)替换为
ExprM a
(树):

其中:

> example1
BinM (LitM 1) Plus (LitM 1)
问题是根本不清楚如何添加
Abs
构造函数。它不可能有真正的形式:

... | Abs a (ExprM a) | ...
因为唯一合理的monad实例必须对参数名执行替换,这没有任何意义。它也容易受到变量捕获的影响


如果有一些聪明的Abs表示法让你坚持一元替代方案,我看不到。

第一步是确保键入的类型正确:
data Expr a=…
,只有这样定义
Functor
Applicative
,才有意义,以及
Expr
Monad
实例。但是,您仍然需要考虑类型具有
Monad
实例意味着什么。作为一个简单的例子,您认为
f>>=lit3
应该是什么意思?首先,感谢您的回复。我对有人如何在数据类型中添加多态“a”而不使其无用感到困惑。其次,f>>=Lit 3是否表示Lit f a?@chepner
Lit 3>>=f
,当然可以。您能解释一下为什么要添加monad实例吗?您已经有了一个正在工作的
eval
,那么您希望monad为您做什么呢?听起来您想要一个读卡器monad。这不会有
Expr
的实例,而是您的
eval
将有一个类似
eval::Expr->Reader Env Value
的类型。然后您的
Env
通过调用执行线程,而无需为每个递归调用显式传递。
instance Applicative ExprM where
  pure = VarM
  (<*>) = ap
instance Monad ExprM where
  VarM x >>= f = f x
  LitM n >>= f = LitM n
  BinM e1 op e2 >>= f = BinM (e1 >>= f) op (e2 >>= f)
body1 = BinM (VarM "x") Plus (VarM "x")

context1 "x" = LitM 1
context1 _ = error "variable not found"

example1 = body1 >>= context1
> example1
BinM (LitM 1) Plus (LitM 1)
... | Abs a (ExprM a) | ...