【发布时间】:2019-02-09 01:30:39
【问题描述】:
注意以下程序:
foo :: Int -> Int -> Bool
foo n x | x == n = True
foo n x | otherwise = foo n (x * 2) || foo n (x * 2 + 1)
main :: IO ()
main = print (foo 10 0)
它实现了一个函数foo,它在两个分支中递归地调用自身,当它沿着树递归时增加第二个参数。如果它的第二个参数等于第一个参数,它“应该”返回True,这是这种情况,因为((0 * 2 + 1) * 2 + 1) * 2 == 10。但这并没有发生,因为 Haskell 在尝试评估左分支深度优先时遇到了困难。
通常,这可以通过实现 BFS 来解决,但在 Haskell 中这样做很尴尬。我想知道是否有任何自动化的或至少不那么突兀的方式来评估递归函数广度优先?
【问题讨论】:
-
@EugeneSh。这与停机问题无关。如果 Haskell 总是首先减少最外层的 redexes,而不是最左边的最内层,则此函数将评估为 true。
-
我不是在问这个问题,我只是问是否有任何方法可以首先评估 Haskell 函数的广度(无论是通过编译器标志还是用户友好的 DSL)。重点是指定递归函数比手动设置 BFS 更容易,因此为此提供库或功能会很方便。
-
不,据我了解,这与评估顺序无关。如果您正在测试
A || B,并且A产生C || D和B到E || F,Haskell 将通过“深度优先”通过A、C和无论接下来发生什么——如果这个分支没有终止,它就永远不会评估B。而 OP 相当合理地询问是否可以编写代码以便A和B都经过测试(顺序无关紧要),然后是C、D、E、F,等等。 -
这与
||的评估顺序无关,它绝对是关于减少递归函数的广度优先(最外面的redexes 优先)或深度优先(最里面的redexes 优先)。请注意,如果您有一个表达式生成||s 的无限树(就像这个),并且如果true出现在该树中的任何位置,那么如果 Haskell 首先评估最外层的 redexes,则此类表达式将始终评估为true. -
这也与 Collatz 猜想无关,因为我不是要求解决问题(即“这个程序是否停止”),我只是在问它是否是可以更改 Haskell 的评估顺序(实际上我在问是否有我可以使用的现有 DSL,因为 GHC 可能无法做到这一点)。它与回答停止问题无关,因为以我提出的方式更改 Haskell 的评估顺序显然并不能保证所有函数都会神奇地停止,尽管这个特殊(和类似)的函数会。
标签: haskell