Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/328.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/qt/7.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
Python parsec.py递归定义_Python_Recursion_Parsec - Fatal编程技术网

Python parsec.py递归定义

Python parsec.py递归定义,python,recursion,parsec,Python,Recursion,Parsec,我喜欢这个图书馆的简朴。遗憾的是,我还没有弄清楚如何进行递归定义: 考虑这个最小的人为例子: import parsec as psc digit = psc.regex("[0-9]") number = lambda: digit ^ (digit + number()) _ = number().parse("42") 正如所料,number()的计算是无限递归的: 回溯(最近一次呼叫最后一次): 文件“”,第1行,在 文件“”,第1行,在 文件“”,第1行,在 文件“”,第1行,在 [

我喜欢这个图书馆的简朴。遗憾的是,我还没有弄清楚如何进行递归定义:

考虑这个最小的人为例子:

import parsec as psc
digit = psc.regex("[0-9]")
number = lambda: digit ^ (digit + number())
_ = number().parse("42")
正如所料,
number()
的计算是无限递归的:

回溯(最近一次呼叫最后一次):
文件“”,第1行,在
文件“”,第1行,在
文件“”,第1行,在
文件“”,第1行,在
[上一行重复了995次]
递归错误:超过最大递归深度
我知道在这个具体的例子中,可以通过将第3行更改为

number = lambda: psc.many1(digit)
但我不确定在一般情况下是否总是可能的

是否可以使数字的解析像中一样递归

<number> ::= <digit><number> | <digit>
::=|
(更新)免责声明:正如我们在评论中发现的,这只适用于parsec.py 3.3以上的版本,该版本(截至2018年8月)是PyPI上可用的最新版本,因此现在您必须从GitHub手动安装开发版本,以便执行此解决方案

更新2:终于发布并修复了该问题


在这样的情况下,我发现“手动扩展”由
parsec
提供的原语并编写一个我们自己的“低级”解析器(即采用
text
index
参数的解析器,而不是从parsec原语构建的解析器)通常是有帮助的,只是为了看看发生了什么。通过从parsec源代码中获取(
^
)的定义并手动插入表达式的组成部分1,我们可以编写一个解析器,我认为它可以满足您的需要:

import parsec as psc
digit = psc.regex("[0-9]")

def number():
  @psc.Parser
  def number_parser(text, index):
    res = (digit + number())(text, index)
    return res if res.status else digit(text, index)
  return number_parser

_ = number().parse("42423")
print(_)
输出:

('4', ('2', ('4', ('2', '3'))))
这样做的原因当然是因为“parser returning function”
number()
仅在实际解析器中有条件地调用,而不是(无条件地)在其自身中调用

编写此函数的一种更简单的方法是根本不使用“解析器返回函数”,而是直接编写解析器本身:

@psc.Parser
def number(text, index):
  return ((digit + number) ^ digit)(text, index)
用法从
number()

最后,parsec.py中是否有一些功能允许您在不使用显式
文本
索引
参数的情况下执行此操作,从而使解析器完全由其他parsec.py原语构建?事实证明,这很合算!从其:

构造解析器最强大的方法是使用generate 室内装修设计师
generate
从生成器创建一个解析器,该解析器 应该生成解析器。这些解析器被依次应用,它们的 使用
.send()
协议将结果发送回生成器。这个 生成器应返回结果或另一个解析器,即 相当于应用它并返回其结果

您可以找到示例用法,从中我们可以清楚地看到:

@psc.generate
def number():
  r = yield (digit + number) ^ digit
  return r
这是因为除了它所具有的所有奇特的生成器魔法之外,
generate
decorator还返回一个本身用
@parsec.Parser
修饰的函数(参见上面链接的源代码),因此生成的、完全修饰的
number
函数将与第二个解决方案中的函数具有相同的类型。因此,我们可以以与
digit
等相同的方式使用它,而不必调用它或任何东西,这就是我们在
yield
表达式中所做的

用法同样只是
number.parse(“42423”)
,它返回与其他两个解决方案相同的内容

也许有更好的解决办法,但这就是我能想到的



1我必须将顺序从
digit^(digit+number())
颠倒为
(digit+number())^digit
,因为第一个只返回第一个数字,然后认为自己完成了。我希望这样可以吗?

如果已经有很多解析器返回函数,或者只是想在风格上保持一致,那么另一种快速解决此问题的方法是使函数延迟求值:

import parsec as psc

def lazy(fn):
  @psc.Parser
  def _lazy(text, index):
    return fn()(text, index)
  return _lazy

digit = lambda: psc.regex("[0-9]")
number = lambda: (digit() + lazy(number)) ^ digit()
print(number().parse("423242"))
印刷品:


您的固定版本实际上就是我想展示的示例。第一种方法只是检测第一个数字,其他两种方法都有相同的递归问题。为了修复它们,我首先定义了:
tokenize=lambda p:p+psc.regex(r“\s+\Z”)
。我在第一种方法中将res改为
res=tokenize(digit)(文本,索引)
。在第二种方法中
返回(标记化(数字)^数字+数字)(文本,索引)
,在第三种方法中
r=yield标记化(数字)^(数字+数字)
。我仍然对这种方法不满意,因为我不得不标记。@jabozzo我的错,第一个例子没有应用脚注中描述的更改(颠倒顺序)-我编辑了它,现在应该可以正常工作了。另外两个例子有什么问题?它们对我来说很好,不会导致无限递归。或者你的意思是它必须是
digit^(digit+number)
,而不是相反?更新后的第一种方法也有无限递归问题。我刚刚将您的函数一个接一个地复制/粘贴到一个文件中,并执行了一个
try:print(number.parse(“24243”))操作,但在每次重新定义之间,递归错误为quo:print(“递归”)
,我得到了3个“递归”。我喜欢在(数字+数字)部分,数字不消耗字符。这正是我正在运行的。@jabozzo是的,可能就是这样,我刚刚尝试了您的parsec版本,它甚至导致了使用Python 3.5的递归-但是如果我直接从Github安装开发版本(
pip install git+https://github.com/sighingnow/parsec.py.git
)它工作正常,因此,我想他们在最新版本之后改变了一些重要的东西。@jabozzo非常欢迎,这很有趣:)从我的测试来看,使其在Github版本中工作的bug修复是,因此实际上这是
joint
+
)的问题。
('4', ('2', ('3', ('2', ('4', '2')))))