我有这个compile
函数,它应该接受一个String然后产生一个Expression。
这就是Expression
的定义方式:
data Expression = Name Char | Lambda Char Expression | Apply Expression Expression
deriving Show
让我们说'编译'功能需要是:
"\\x.\\y.yx"
因此,最后compile
函数应该将其作为最终的表达式:
Lambda 'x' (Lambda 'y' (Name 'y') (Name 'x'))
这是compile
函数:
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
目前,此功能可以避免表达式的最后一部分((Name 'x')
)。我的问题是:
如果我产生Name
,那么这个函数如何继续使用更多Name
s我不能继续使用表达式的其余部分调用相同的函数?由于Expression
的定义是这样的,如果Expression
是Name
,它只有一个Name
而且没有更多,那么就没有表达式了。
我的意思是,我怎样才能接受Name
中的每一个Expression
,'告诉' Haskell我想继续寻找Name
而不只是在找到Name
时停止。
我认为可能创建另一个函数是一个好主意,但我无法弄清楚如何多次调用该函数。事实是,我并不习惯在Haskell中进行递归,我真的需要一些帮助。
我该怎么做?
答案 0 :(得分:3)
直接在String
上使用递归进行解析虽然可行但是很棘手。在你的lambda演算语言中,例如处理(嵌套)括号需要一些小心。
如果你想尝试这一点,至少你应该研究LL parsers如何工作:如何编写LL语法,如何处理先行符号,以及一般的形式语言理论的基础知识。
如果你想通过"来学习这些",请尝试使用Parsec等解析器库。
作为一个小建议:虽然大多数关于lambda演算的论文只使用单字母变量并写例如" XY"对于应用程序,在实现中,您确实需要更长的变量名称,即使它是以应用术语之间需要空格为代价的(例如" x y")。这使得解析器稍微难以编写,但值得付出努力。