Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Parsing 定点组合器如何使递归构造终止?_Parsing_Haskell_Recursion_Compiler Construction_Combinators - Fatal编程技术网

Parsing 定点组合器如何使递归构造终止?

Parsing 定点组合器如何使递归构造终止?,parsing,haskell,recursion,compiler-construction,combinators,Parsing,Haskell,Recursion,Compiler Construction,Combinators,提供一种匿名函数引用自身或构建相互递归结构的方法。虽然它们在lambda演算中很有用,但在现代编程语言中基本上是多余的,因为大多数(如果不是全部的话)都支持递归、lambda和闭包 此外,定点组合符可以使递归构造(如左递归语法分析器)终止。考虑一下,谁证明了他的实现的终止,但实际上从来没有提到它是如何工作的(它只是从晶格理论到Haskell实现的逐步推导),以及为什么他需要一个已经支持递归的语言的定点组合器。 它是如何工作的,为什么他需要一个定点组合器?从5.3结尾的快速扫描中,利克曼写道,“如

提供一种匿名函数引用自身或构建相互递归结构的方法。虽然它们在lambda演算中很有用,但在现代编程语言中基本上是多余的,因为大多数(如果不是全部的话)都支持递归、lambda和闭包

此外,定点组合符可以使递归构造(如左递归语法分析器)终止。考虑一下,谁证明了他的实现的终止,但实际上从来没有提到它是如何工作的(它只是从晶格理论到Haskell实现的逐步推导),以及为什么他需要一个已经支持递归的语言的定点组合器。
它是如何工作的,为什么他需要一个定点组合器?

从5.3结尾的快速扫描中,利克曼写道,“如上所述,可以确保fixS在所有连续输入上都有足够的生产力。”

关键是让fixpoint操作符产生足够的输出,以便继续解析。对于一般的
修复程序::(a->a)->a
,您不能这样做,但是将
a
专门化为
设置a
,或者稍后的
解析器a
,可以提供足够的结构(即晶格结构)


同样,我只是粗略地看了一下这篇论文,但我认为语句“
h::Parser a->Parser a
保持生产力==>
fixP h
是生产力”的证明(在第5.5节)是关键。

当然。下面是一个简单的右递归语法,有三条规则:

S -> b T
T -> a S
T -> a
这三条规则让我们构建一个解析器来识别这些字符串:

type Parser = String -> (Bool, String)
s :: Parser
s "" = (False, "")
s (c : cs) = if c == 'b' then t cs else (False, cs)

t :: Parser
t "" = (False, "")
t (c : cs) 
  | c == 'a' && cs == "" = (True, "") 
  | c /= 'a' = (False, cs)
  | otherwise = s cs
如果您想进行更一般的解析,只需专门化
Bool
,以具有一些数据结构,可能存储在
Maybe
中以指示失败。如果S也有一些其他规则,例如
S->T
T->b
,则在解析失败时返回
(False,uuuuuuuuuuuu)
。然后,当我们得到一个“b”后跟(False,uuu uu)时,我们倒带尝试
S->T
。这类语法只需稍加润色和递归即可完成

上面的三条规则将成功地匹配字符串,如“ba”、“baba”等。我们也可以将这些字符串以递归的方式写为:

S -> T a
T -> S b
T -> b
如果您尝试编写上面相同的解析器,会发生什么?一个无限循环,如果你在看字符串的前面。问题是函数S将首先调用函数T,然后T将首先调用函数S,它们将无限地相互递归。计算机不够聪明,不知道后置条件(“后接a”,“后接b”)使进一步的解决方案变得不可能;它只是下降到你的职能和信任,你知道你在做什么


一个好的定点组合器有什么帮助?好吧,把这些规则想象成描述一棵树:然后函数求值首先遍历树的深度,这个特定的树在那个方向是无限的。另一方面,宽度优先遍历可以基于这些规则,并且可以拾取使用尽可能少的函数的结果,这是基于此语法的特定函数的“最小不动点”。这就是为什么在描述这些规则时,正确的定点组合符(基于论文中的
diag
或晶格理论组合符)可以终止,而朴素的递归不会终止。

谢谢你的回答。关于你关于不动点操作符输出的陈述,有一点我不明白:据我所知,它是一个单一的值
x
,因此对于某些函数
f
,这对继续解析来说是足够的还是不够的?问得好!考虑一个简化的例子,函数<代码> f=(1:)::[INT] > [INT] < /代码>。
f
的最小不动点是一个无限多个不动点的列表,因此不能全部计算。但是您不需要整个列表就可以计算
take 5(fix f)
!论文中使问题复杂化的是,
Parser
(以及
Set
,在较小程度上)并不像
[Int]
那么简单,所以懒惰并不能自动起作用。这对你有意义吗?我想它有意义:
fixP
让我得到一个解析器,它可以生成最大的一组唯一解析树,这样
h(p)=p
就成立了,其中
h
fixP
的第一个参数和
p
我的解析器。因此,
h
仅用于“检查”给定的解析器是否与原始的、非生产性的解析器等效?谢谢您的回答,这非常有意义。然而,如果combinator只将遍历策略从深度优先更改为广度优先,那么作者为什么不明确说明呢?宽度优先已经在83年被使用。实际上,他拒绝使用基于格理论的更好的组合器的diag(我认为这是一个明确的BFS),这就是为什么有更多的数学。固定点的概念是由a
fixf=let a=fa在a
中捕获的,
fix:(x->x)->x
。将其称为
x
上的修复程序。例如,您可以在
fix(const 0)
fix(1:)
fix(\f n->如果n<10,则n:f(n+1)else[])3上使用此选项。他的想法是我们可以为
A->[B]
做更好的固定点,因为
[B]
是一个“晶格”,所以我们在
s->[(A,s)]
上得到更好的固定点。(他的方法是否与[]的MonadFix实例相同?我不知道。)