模式匹配元组不是完全懒惰的吗?

Dar*_*ith 3 haskell lazy-evaluation

我在 Haskell 中遇到了一些非常不直观的行为,我不确定它是否是 Haskell 中的错误。如果这是预期行为,具体是什么导致无限循环?

import Data.Function (fix)

main=putStrLn$show$fst$
    fix (\rec-> (\(a1,a2)->(3,7)) rec)
Run Code Online (Sandbox Code Playgroud)

无限循环,我假设是因为将 rec 模式匹配到 rec (a1,a2) 它评估。但我觉得它不应该需要,因为一切都会匹配。例如,这些都可以正常工作:

    fix (\rec-> (\a->(3,7)) rec)
    fix (\rec-> (\a->let (a1,a2)=a in (3,7)) rec)
Run Code Online (Sandbox Code Playgroud)

有趣的是这退出错误

    fix (\rec-> (\(a1,a2)->(3,7)) undefined)
Run Code Online (Sandbox Code Playgroud)

但是我可以发誓,我遇到这种行为(更复杂)的原始代码在这种情况下实际上会起作用。我可以尝试重新创建它。

Dan*_*ner 13

正确,元组模式匹配不是懒惰的。事实上,除了两个值得注意的例外,没有模式匹配是 lazy。粗略地讲,模式匹配的“要点”是强制对比赛的监督者进行评估。

当然,模式匹配可能出现在懒惰意味着永远不会执行的地方;例如,

const 3 (case loop of (_, _) -> "hi!")
Run Code Online (Sandbox Code Playgroud)

不会循环。但这并不是因为匹配是惰性的——而是因为它const是惰性的并且从不导致执行匹配。你的let例子是类似的,因为语义let是它绑定的变量在评估let.

两个值得注意的例外之一是特殊的模式修饰符,~; 放在~模式之前表示使匹配变得惰性,因此向编译器声明修改后的模式始终匹配。(如果它不匹配,一旦强制绑定变量之一,您就会崩溃,而不是通常的下一个模式行为!)因此,对您的解决方法fix是:

fix (\rec -> (\ ~(a1, a2) -> (3, 7)) rec)
Run Code Online (Sandbox Code Playgroud)

当然,rec不需要明确的名称。你也可以这样写:

fix (\ ~(a1, a2) -> (3, 7))
Run Code Online (Sandbox Code Playgroud)

另一个值得注意的例外是新类型匹配,这里不相关。

  • @DarrenSmith,不,元组不能用“newtype”定义。只有单个构造函数、*单字段*类型可以。它们是否“应该”取决于上下文(通常是,有时不是)。 (2认同)