您如何评估Haskell中的Lambda表达?

发布于 2025-02-04 13:11:18 字数 3336 浏览 3 评论 0原文

lambdas具有:(lambda(var)expr)的形式,并表示一个匿名函数,该函数获取单个参数。 Miniracket中没有多重拨号功能。

data Expr
  = LambdaExpr String Expr
  | LetExpr String Expr Expr
  deriving (Show, Eq)

评估lambda应该导致闭合,即功能主体,参数的名称以及定义函数时的当前环境。然后在应用功能时使用此环境,因为它应该让我们知道哪些绑定在此之前可用。

这是我的evallambdaexpr,

-- evaluate lambdas, which requires storing the current environment as the closure,
-- this should result in a ClosureVal, which can later be used for apply, if it's
-- a totally anonymous function, then "" is the function name, otherwise if it was
-- built with a let expression, then the let name is its name.
evalLambdaExpr :: Evaluator Value
evalLambdaExpr = do
  (env, LambdaExpr letName valexpr) <- next
  case getValue (eval evalExpr (env, valexpr)) of
    Right (ClosureVal "" argName funBody cenv) ->
      let env = Env.bind "" (ClosureVal "" argName funBody cenv) cenv
       in case getValue (eval evalExpr (env, funBody)) of
            Right v -> return v
            Left err -> evalError err
    Right nameval ->
      case getValue (eval evalExpr (bind letName nameval env, valexpr)) of
        Right letval -> return letval
        Left err -> evalError err
    Left err -> evalError err

-- and an Alternative ...
instance Alternative Evaluator where
  empty = failEval "no matching evaluation"

-- define the type for values, which in our mini language
-- can be integers, bools, pairs, or closures
data Value
  = IntVal Integer
  | BoolVal Bool
  | PairVal (Value, Value)
  | ClosureVal String String Expr ValueEnv
  deriving (Show, Eq)

newtype Evaluator a = E {eval :: (ValueEnv, Expr) -> Either ErrorT (a, (ValueEnv, Expr))}

-- this is the basic evaluator, it ends when ast is an EmptyExpr, but otherwise,
-- we get the the environment and expr returned
next :: Evaluator (ValueEnv, Expr)
next =
  E
    ( \parserState -> case parserState of
        (_, EmptyExpr) -> Left $ EvalError "no more expressions"
        (env, x) -> Right ((env, x), (env, EmptyExpr))
    )

evalError :: ErrorT -> Evaluator a
evalError err = E (\_ -> Left err)

我的evallambdaexpr总是返回左;这是为什么?

例如,我的evalletexpr正常工作,这就是我所拥有的:

-- Evaluate a let expression. This first evaluates the
-- argument to the identifier. Once that is evaluated, I
-- bind the value to the name in a new environment, then
-- I evaluate the body with this new environment
evalLetExpr :: Evaluator Value
evalLetExpr = do
  (env, LetExpr letName valexpr body) <- next
  case getValue (eval evalExpr (env, valexpr)) of
    -- we got a closure from it, but it doesn't have a name,
    -- so let's add that to the closure as its 'funname'
    Right (ClosureVal "" argName funBody cenv) ->
      let env' = Env.bind letName (ClosureVal letName argName funBody cenv) cenv
       in case getValue (eval evalExpr (env', body)) of
            Right v -> return v
            Left err -> evalError err
    Right nameval ->
      case getValue (eval evalExpr (bind letName nameval env, body)) of
        Right letval -> return letval
        Left err -> evalError err
    Left err -> evalError err

对于两个评估者,我都评论了他们在上面的工作。为什么evalstr”(lambda(x)true)”返回left(evalerror“无匹配评估”)

我知道这不是我的解析,因为它有效。

Lambdas have the form: (lambda (var) expr) and represent an anonymous function that takes a single argument. There are no multi-argument functions in MiniRacket.

data Expr
  = LambdaExpr String Expr
  | LetExpr String Expr Expr
  deriving (Show, Eq)

Evaluating a lambda should result in a closure, which is the function body, the name of the argument to it, and the current environment when the function was defined. This environment is then used when applying the function because it should let us know which bindings were available up until that point.

Here is my evalLambdaExpr

-- evaluate lambdas, which requires storing the current environment as the closure,
-- this should result in a ClosureVal, which can later be used for apply, if it's
-- a totally anonymous function, then "" is the function name, otherwise if it was
-- built with a let expression, then the let name is its name.
evalLambdaExpr :: Evaluator Value
evalLambdaExpr = do
  (env, LambdaExpr letName valexpr) <- next
  case getValue (eval evalExpr (env, valexpr)) of
    Right (ClosureVal "" argName funBody cenv) ->
      let env = Env.bind "" (ClosureVal "" argName funBody cenv) cenv
       in case getValue (eval evalExpr (env, funBody)) of
            Right v -> return v
            Left err -> evalError err
    Right nameval ->
      case getValue (eval evalExpr (bind letName nameval env, valexpr)) of
        Right letval -> return letval
        Left err -> evalError err
    Left err -> evalError err

-- and an Alternative ...
instance Alternative Evaluator where
  empty = failEval "no matching evaluation"

-- define the type for values, which in our mini language
-- can be integers, bools, pairs, or closures
data Value
  = IntVal Integer
  | BoolVal Bool
  | PairVal (Value, Value)
  | ClosureVal String String Expr ValueEnv
  deriving (Show, Eq)

newtype Evaluator a = E {eval :: (ValueEnv, Expr) -> Either ErrorT (a, (ValueEnv, Expr))}

-- this is the basic evaluator, it ends when ast is an EmptyExpr, but otherwise,
-- we get the the environment and expr returned
next :: Evaluator (ValueEnv, Expr)
next =
  E
    ( \parserState -> case parserState of
        (_, EmptyExpr) -> Left $ EvalError "no more expressions"
        (env, x) -> Right ((env, x), (env, EmptyExpr))
    )

evalError :: ErrorT -> Evaluator a
evalError err = E (\_ -> Left err)

My evalLambdaExpr is always returning a Left; why is that?

As an example, my evalLetExpr is working correctly and this is what I have:

-- Evaluate a let expression. This first evaluates the
-- argument to the identifier. Once that is evaluated, I
-- bind the value to the name in a new environment, then
-- I evaluate the body with this new environment
evalLetExpr :: Evaluator Value
evalLetExpr = do
  (env, LetExpr letName valexpr body) <- next
  case getValue (eval evalExpr (env, valexpr)) of
    -- we got a closure from it, but it doesn't have a name,
    -- so let's add that to the closure as its 'funname'
    Right (ClosureVal "" argName funBody cenv) ->
      let env' = Env.bind letName (ClosureVal letName argName funBody cenv) cenv
       in case getValue (eval evalExpr (env', body)) of
            Right v -> return v
            Left err -> evalError err
    Right nameval ->
      case getValue (eval evalExpr (bind letName nameval env, body)) of
        Right letval -> return letval
        Left err -> evalError err
    Left err -> evalError err

For both evaluators, I commented what they do on above them. Why is evalStr "(lambda (x) true)" returning Left (EvalError "no matching evaluation")?

I know it's not my parsing because that works.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

我最亲爱的 2025-02-11 13:11:18
evalLambdaExpr :: Evaluator Value
evalLambdaExpr = do
  (env, LambdaExpr letName valexpr) <- next
   case getValue (eval evalExpr (env, valexpr)) of

唔。据我了解,这说明为了评估(lambda(x)(+ x 1)),我们应该立即评估(+ x 1)。那不是应该发生的事情 - 只有在应用闭合时才能评估lambda的主体 - 毕竟,我们甚至不知道x的价值应该在该表达式中。

我不确定这是否是导致您的错误的原因,但是我希望这会导致各种怪异的事情发生在您尝试在错误的时间评估未限制变量的表达式时发生。

通常,一个人需要expr构造函数将lambda应用于参数。

evalLambdaExpr :: Evaluator Value
evalLambdaExpr = do
  (env, LambdaExpr letName valexpr) <- next
   case getValue (eval evalExpr (env, valexpr)) of

Hmm. As far as I understand, this says that in order to evaluate (lambda (x) (+ x 1)), we should evaluate (+ x 1) immediately. That is not what should happen -- the body of the lambda should only be evaluated when the closure is applied -- after all, we don't even know what the value of x should be in that expression.

I am not sure if this is what is causing your error, but I would expect this to cause all sorts of weird things to happen as you try to evaluate expressions at the wrong time with unbound variables.

One typically needs an Expr constructor for applying a lambda to an argument.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文