Haskell帮助:用新变量替换lambda术语中的术语!(简单的错误需要纠正…)

Haskell帮助:用新变量替换lambda术语中的术语!(简单的错误需要纠正…),haskell,functional-programming,lambda-calculus,Haskell,Functional Programming,Lambda Calculus,我正在尝试编写一个函数,当传递时: variables VX = ["v1",..."vn"] 一个术语,将分别用VX中的变量替换传递的术语中的所有术语 我的函数在一定程度上起作用,例如: S ((\a. \x. (\y. a c) x b) (\f. \x. x) 0) 它返回: S (V1 V1 0) 而不是它应该返回什么: S (V1 V2 0) 下面是我的函数和测试。也许有人能发现我犯的错误吗 termToExpression :: [Var] -> Term ->

我正在尝试编写一个函数,当传递时:

variables VX = ["v1",..."vn"]
一个
术语
,将分别用VX中的
变量替换传递的
术语
中的所有
术语

我的函数在一定程度上起作用,例如:

S ((\a. \x. (\y. a c) x b) (\f. \x. x) 0)
它返回:

S (V1 V1 0) 
而不是它应该返回什么:

S (V1 V2 0) 
下面是我的函数和测试。也许有人能发现我犯的错误吗

termToExpression :: [Var] -> Term -> Expression
termToExpression [] a = termToExpr a
termToExpression _ (TermVar y) = ExpressionVar y
termToExpression (x : _) (TermLambda a b) = ExpressionVar x 
termToExpression (x : xs) (TermApp n m) = ExpressionApp (termToExpression (x : xs) n) (termToExpression (x : xs) m)
问题是

ExpressionApp (termToExpression (x : xs) n) (termToExpression (x : xs) m)
进行两次递归调用,直观地说,第一次调用应该“使用”任意数量的变量来生成其输出。之后,第二个递归调用不应该使用第一个调用已经“使用”的变量

从某种意义上说,每次调用都会修改某种状态:变量列表被部分使用

要对此进行建模,首先需要编写一个辅助递归函数,该函数与新的lambda项一起返回尚未使用的变量列表

aux :: [Var] -> Term -> (Expression, [Var])
现在,当您需要对
aux
进行两次递归调用时,可以进行第一次递归调用,从结果中获取未使用变量的列表,然后使用该列表进行第二次递归调用

(更高级的解决方案是使用
State[Var]
monad,但我想您应该编写一个基本的解决方案。)

问题在于

ExpressionApp (termToExpression (x : xs) n) (termToExpression (x : xs) m)
进行两次递归调用,直观地说,第一次调用应该“使用”任意数量的变量来生成其输出。之后,第二个递归调用不应该使用第一个调用已经“使用”的变量

从某种意义上说,每次调用都会修改某种状态:变量列表被部分使用

要对此进行建模,首先需要编写一个辅助递归函数,该函数与新的lambda项一起返回尚未使用的变量列表

aux :: [Var] -> Term -> (Expression, [Var])
现在,当您需要对
aux
进行两次递归调用时,可以进行第一次递归调用,从结果中获取未使用变量的列表,然后使用该列表进行第二次递归调用


(更高级的解决方案是使用
State[Var]
monad,但我想您应该编写一个基本解决方案。)

您的
TermApp
案例不会在第二次递归调用中删除
x
。它将
x
放回堆栈的前面,这样就永远不会访问
xs
的其余部分。@4现在我明白了,谢谢。但是现在将这一行更改为
termToExpression(x:xs)(Apply n m)=ExpressionApp(termToExpression(x:xs)n)(termToExpression(xs)m)
,它返回
S(V2(\f.\x.x)0)
而不是所需的`S(V1 V2 0)。我想我不明白
Show
实例是如何工作的。你能展示一下你的代码中的
example2
是什么样子吗?“用变量替换一个术语”对于lambda演算来说是一件不寻常的事情。术语是一个复合值(可能包含其他术语),而变量是另一个术语的占位符。用一个术语(称为替换)替换变量更为常见。为什么要这样做?@4castle当然,example2的定义如下:
example2=Apply(变量“S”)(Apply(Apply-example(数字0))(变量“0”)
您的
TermApp
案例不会在第二次递归调用中删除
x
。它将
x
放回堆栈的前面,这样就永远不会访问
xs
的其余部分。@4现在我明白了,谢谢。但是现在将这一行更改为
termToExpression(x:xs)(Apply n m)=ExpressionApp(termToExpression(x:xs)n)(termToExpression(xs)m)
,它返回
S(V2(\f.\x.x)0)
而不是所需的`S(V1 V2 0)。我想我不明白
Show
实例是如何工作的。你能展示一下你的代码中的
example2
是什么样子吗?“用变量替换一个术语”对于lambda演算来说是一件不寻常的事情。术语是一个复合值(可能包含其他术语),而变量是另一个术语的占位符。用一个术语(称为替换)替换变量更为常见。为什么要这样做?@4当然,示例2的定义如下:
example2=Apply(变量“S”)(Apply(应用示例(数字0))(变量“0”))