如何在 haskell 中计算带有 curried 参数的函数?

How to evaluate a function with curried argument in haskell?

提问人:Avunz 提问时间:11/5/2023 最后编辑:ChrisAvunz 更新时间:11/7/2023 访问量:66

问:

我正在编写一个表达式计算器,定义如下:

eval :: LState -> Env -> Lexp -> (LState, Value)

其中 LState 是内存。Env:Variable 和 Value.Lexp 的映射定义如下:

data Lexp = Lid Var | Lfuncall Lexp [Lexp]

(Lexp 还有更多,但其余的对解决我的问题没有用。

值定义如下:

data Value = Vnum Int
           | Vbool Bool
           | Vref Int
           | Vfun ((LState, Value) -> (LState, Value))

使用模式匹配,我编写了函数的第一部分:eval s env (Lfuncall func (arg:args)) =

现在,我尝试使用 foldl 和 lambda 函数,但没有任何效果。

eval s env (Lfuncall func (arg:args)) =   let arg' = eval s env arg
        args' = map (eval s env) args
    in
        case eval s env func of
            (_, Vfun func') -> foldl func' arg' args'
            _ -> error "error"

然而,这是行不通的,因为 func' 需要,但它只是 .Lambdas 在解决这个问题方面无处可去。(LState, Value) -> (LState, Value) -> (LState, Value)(LState, Value) -> (LState, Value)

关于我应该尝试探索什么的任何提示或想法?

Haskell 模式匹配 折叠 评估器

评论


答:

2赞 luqui 11/5/2023 #1

你走在正确的轨道上,左折。让我们仔细考虑一下我们将折叠什么功能。它需要一个应该(但不能保证)是一个函数,以及一个将被计算的参数,并且应该返回一个(如果有更多的参数,它将扮演下一个函数的角色)。所以,乍一看脸红,是类型只是:ValueLexpValue

folder :: Value -> Lexp -> Value
--        ^ accumulator (function)
--                 ^ argument
--                         ^ result (used as next accumulator)

如果我们适用于此:foldl

foldl folder :: Value -> [Lexp] -> Value

它采用初始函数和参数列表。

但这并不能处理状态部分。我们需要将当前状态作为累加器的一部分,而不仅仅是当前函数,并且需要返回最终状态。这些参数没有自己的状态。因此,我们的类型为:

folder :: (LState, Value) -> Lexp -> (LState, Value)

由此产生的折叠将是:

foldl folder :: (LState, Value) -> [Lexp] -> (LState, Value)

获取初始状态、初始函数、参数列表,并给出最终状态和最终结果。这加起来。所以现在我们需要做的就是用这个签名写,我把它作为一个练习。folder

需要记住的一些事情。永远不要丢弃一个状态或两次使用它——这被称为线性,它对于“有状态计算”的想法非常重要。状态计算通常具有这种模式

 let (s1, x) = something s0
     (s2, y) = something s1
     (s3, z) = something s2
 in  (s3, something)

因此,我们从上一步中获取结果状态并将其传递给下一步,返回最后一步。

为了调用,必须能够访问 。为此,可以在子句中定义:evalfolderenvfolderwhere

eval s env (Lfuncall func args) = ...
    where
    folder :: (LState, Value) -> Lexp -> (LState, Value)
    folder (s0, Vfun f) argExp = -- use env freely here

我希望这会有所帮助。我故意对一些细节有点含糊不清,因为你真的只需要用头撞它才能得到模式,如果有什么需要进一步澄清的,请告诉我。

评论

0赞 Avunz 11/5/2023
成功了。非常感谢您解释这样的概念。你做得很好,我学到了很多东西。也谢谢你含糊其辞,我喜欢自己弄清楚东西。