Lambda演算Haskell的Beta转换

Lambda演算Haskell的Beta转换,haskell,lambda-calculus,Haskell,Lambda Calculus,我想实现一个函数,该函数对lambda表达式进行beta缩减,其中lambda表达式的类型为: data Expr = App Expr Expr | Abs Int Expr | Var Int deriving (Show,Eq) 到目前为止,我的评估职能是: eval1cbv :: Expr -> Expr eval1cbv (Var x) = (Var x) eval1cbv (Abs x e) = (Abs x e) eval1cbv (App (Abs x e1) e@(Ab

我想实现一个函数,该函数对lambda表达式进行beta缩减,其中lambda表达式的类型为:

data Expr = App Expr Expr | Abs Int Expr | Var Int deriving (Show,Eq)
到目前为止,我的评估职能是:

eval1cbv :: Expr -> Expr
eval1cbv (Var x) = (Var x)
eval1cbv (Abs x e) = (Abs x e)
eval1cbv (App (Abs x e1) e@(Abs y e2)) = eval1cbv (subst e1 x e)
eval1cbv (App e@(Abs x e1) e2) =  eval1cbv (subst e2 x e)  
eval1cbv (App e1 e2) = (App (eval1cbv e1) e2)
其中
subst
是用于定义替换的函数

然而,当我尝试使用beta reduce来减少表达式时,我得到了一个非穷举模式错误,我无法理解为什么。我能做的是在底部添加一个额外的案例,如下所示:

eval :: Expr -> Expr
eval (Abs x e) = (Abs x e)
eval (App (Abs x e1) e@(Abs y e2)) = subst e1 x e
eval (App e@(Abs x e1) e2) = App e (eval e2)
eval (App e1 e2) = App (eval e1) e2
eval (Var x) = Var x
但是,如果我这样做了,那么lambda表达式就不会被缩减,这意味着输入与函数的输出是相同的

因此,如果我尝试评估一个简单的案例,如:

eval (App (Abs 1 (Abs 2 (Var 1))) (Var 3)) 
评估(应用程序(Abs 2(Var 2))(Abs 3(Var 3)))它工作正常-给出> Abs 3(变量3)

但是当我为一个更大的测试用例运行它时,比如:

评估(应用程序(Abs 1(Abs 2(Var 1)))(Var 3))我得到:

  • 如果使用第一个函数而不添加最后一个案例,则为非穷举模式
  • 或者完全相同的表达式App(abs1(abs2(Var 1)))(Var 3),如果我加上最后一个案例,它显然不会减少
  • 谁能帮我弄清楚这个问题吗?:)

    但是当我为一个更大的测试用例运行它时,比如:

    eval (App (Abs 1 (Abs 2 (Var 1))) (Var 3)) 
    
    当您尝试将
    Abs x e
    的形式应用于
    Var y
    时,您就在这个分支中

    所以你有

    这不是你想做的。
    (Abs x e)
    (Var y)
    均为正常形式(即已评估),因此您应该替换。您似乎只处理lambda,而不处理变量


    你的代码有更多的问题。考虑这个分支,

    结果总是一个
    应用程序
    。例如,如果
    eval e1=Abs x E
    则结果为
    App(Abs x E)e2
    。它停止在那里,不执行进一步的评估

    并考虑这个分支,

    如果替换的结果是一个应用术语,会发生什么?结果会被评估吗


    编辑

    关于您的变更,假设
    LamApp e1 e2
    您之前遵循了价值评估策略(即,您在替换之前正在评估
    e2
    )。那已经过去了

    这里它是一个lambda,因此不需要计算

    在这里,不管e2是什么,都要进行替换,因此您的操作与之前完全相同。您当时不需要前面的案例,现在正在遵循按姓名呼叫评估策略。我不知道这是不是你想要的。此外,您在这里使用错误的参数调用
    subst
    。我想你的意思是
    subst e1 x e2
    ,你不需要
    @e

    这里您只需要评估第一个参数,它与按名称调用策略一致。但我也不知道这是否是你的意图


    您是否考虑过该错误可能在函数
    subst
    中?应用
    subst
    后,您不需要
    eval
    ?您还应该提供What's
    LamExpr
    ?非常感谢您的回答!我试着把我的代码改成上面的代码,这样可以稍微减少一点,但不能完全减少。您能看一下并告诉我任何建议的更改吗?:)@JoeBowtie对你的新版本进行了编辑,并发表了一些评论。
      App (Abs x e) (Var y)
    = App (Abs x e) (eval (Var y))
    = App (Abs x e) (Var y)
    
    eval (App e1 e2) = App (eval e1) e2
    
    eval (App (Abs x e1) e@(Abs y e2)) = subst e1 x e
    
    eval1cbv (LamApp (LamAbs x e1) e@(LamAbs y e2)) = eval1cbv (subst e1 x e)
    
    eval1cbv (LamApp e@(LamAbs x e1) e2) =  eval1cbv (subst e2 x e)  
    
    eval1cbv (LamApp e1 e2) = (LamApp (eval1cbv e1) e2)