Haskell中的递归问题

Haskell中的递归问题,haskell,recursion,lambda,Haskell,Recursion,Lambda,我有一个compile函数,它应该接受一个字符串,然后生成一个表达式 以下是表达式的定义: data Expression = Name Char | Lambda Char Expression | Apply Expression Expression deriving Show 假设“compile”函数采用的字符串为: "\\x.\\y.yx" 因此,在最后,compile函数应该生成以下表达式作为最终表达式: Lambda 'x' (Lambda 'y' (Nam

我有一个
compile
函数,它应该接受一个字符串,然后生成一个表达式

以下是
表达式
的定义:

data Expression = Name Char | Lambda Char Expression | Apply Expression Expression 
        deriving Show
假设“compile”函数采用的字符串为:

"\\x.\\y.yx"
因此,在最后,
compile
函数应该生成以下表达式作为最终表达式:

Lambda 'x' (Lambda 'y' (Name 'y') (Name 'x'))
这是
编译
函数:

compile :: [Char] -> Expression
compile (x:xs) = if [x] == "\\" then Lambda (head xs) (compile (tail xs))
                    else if [x] == "." then compile xs
                    else if null xs then Name x
                    else Name x
目前,此函数排除了表达式的最后一部分(
(名称“x”)
)。我的问题是:

如果一旦我产生了一个
名称
我就不能继续用表达式的其余部分调用同一个函数,那么这个函数如何继续使用更多的
名称
s?由于
表达式
是这样定义的,如果
表达式
是一个
名称
,那么它只有一个
名称
,没有更多,就没有表达式了

我的意思是,我怎么能把
表达式中的每一个
名称
,“告诉”Haskell我想继续寻找
名称
,而不只是在找到单个
名称时停止

我认为创建另一个函数是个好主意,但我不知道如何多次调用该函数。事实上,我并不真正习惯Haskell中的递归,我真的需要一些帮助


如何做到这一点?

直接使用
字符串上的递归进行解析,虽然可行,但很棘手。在lambda演算语言中,例如,处理(嵌套的)括号需要一些注意

如果你想尝试这样做,至少你应该了解它是如何工作的:如何编写LL语法,如何处理先行符号,以及一般形式语言理论的基础

如果您希望“通过实践”学习这些,请尝试使用解析器库,例如


作为一个小建议:虽然大多数关于lambda演算的论文只使用单字母变量,并为应用程序编写例如“xy”,但在一个实现中,您确实需要更长的变量名称,即使这是以在应用术语之间需要空格(例如“xy”)为代价的。这使得解析器的编写稍微困难一些,但值得付出努力。

实际上,使用直接递归编写LL解析器一点也不难。这很乏味(好吧,有一些很棘手的情况,但在解析lambda演算表达式时不会出现任何问题)@Cubic如果您了解什么是all语法,以及一些基本理论,那么编程(即使是在命令式语言中!)确实很容易。然而,我并不期望一个普通的程序员在没有接触过任何正式语言的情况下自己重新发现它。我们需要理解(对于手边的语言)您可以编写语法,这样一个先行标记就足以解决每个非终结符的结果中的不确定性。好吧,您通常可以只使用一个先行标记。LL(1)毕竟没有涵盖所有上下文无关的语法。