【问题标题】:How `fix f = let {x = f x} in x` is evaluated?如何评估 `fix f = let {x = f x} in x`?
【发布时间】:2021-03-15 08:23:03
【问题描述】:

fix f = let {x = f x} in x

谈到let,我认为let P = Q in R 会评估Q -> Q' 然后P 被R 中的Q' 替换,或者:R[P -> Q']

但是在fix的定义中Q依赖于R,那么如何评估呢?

我想这是关于惰性评估的。 Q' 变成了一个 thunk,但我无法在脑海中推理。

作为上下文,我正在查看 Y 组合子,它应该找到一个函数的不动点,所以如果我有这个函数,one x = 1,那么fix one == 1 必须成立对吧?

所以fix one = let {x = one x} in x,但我看不出1 会如何从中产生。

【问题讨论】:

    标签: haskell lazy-evaluation evaluation fixpoint-combinators


    【解决方案1】:

    谈到 let,我认为 let P = Q in R 会评估 Q -> Q' 然后 PR 中被 Q' 替换,或者:R[P -> Q']

    在道德上,是的,但 P 不会立即评估,而是在需要时评估。

    但是在修复定义中Q 依赖于R,那么如何评估呢?

    Q 不依赖于R,它依赖于P。这使得P 递归地依赖于自身。这可能导致几种不同的结果。粗略地说:

    • 如果Q 在评估P 之前无法返回其结果的任何部分,则P 表示无限递归计算,它不会终止。例如,

      let x = x + 1 in x     -- loops forever with no result
      -- (GHC is able to catch this specific case and raise an exception instead,
      -- but it's an irrelevant detail)
      
    • 如果Q 可以在需要评估P 之前返回其结果的一部分,它会这样做。

      let x = 2 : x in x
      -- x = 2 : .... can be generated immediately
      -- This results in the infinite list 2:2:2:2:2:.....
      
      let x = (32, 10 + fst x) in x
      -- x = (32, ...) can be generated immediately
      -- hence x = (32, 10 + fst (32, ...)) = (32, 10+32) = (32, 42)
      

    我想这是关于惰性评估的。 Q' 变成了一个 thunk,但我无法在脑海中推理。

    P 与 thunk 相关联。重要的是这个 thunk 是否在返回部分输出之前调用自己。

    作为上下文,我正在查看 Y 组合器,它应该找到一个函数的固定点,所以如果我有这个函数。 one x = 1,那么fix one == 1一定要持有,对吧?

    是的。

    所以fix one = let x = one x in x,但我不明白为什么会出现1

    我们可以这样计算:

    fix one
     = {- definition of fix -}
    let x = one x in x
     = {- definition of x -}
    let x = one x in one x
     = {- definition of one -}
    let x = one x in 1
     = {- x is now irrelevant -}
    1
    

    只需扩展定义。保留递归定义以备不时之需。

    【讨论】:

    • 太棒了,非常感谢,。这是等式推理?我需要练习一下
    • @geckos 是的,这是等式推理。请记住,GHC 可能不会完全遵循这些步骤(它的运行时系统相当复杂,使用了大量优化),但它保证会导致相同的结果。
    • (在看到你的帖子结尾之前我太仓促发布我的答案......:))
    • @geckos 是的。为了迂腐,我会说f x 依赖于x,而不是f 依赖于x。你说后者只是因为你知道f应用于x,所以你提到f但你想到的是f x
    • @geckos 这是一个递归定义,所以你在它完全定义之前使用它。在命令式过程语言中,您可以编写一个函数 def x(): if ... then use x() else ... 来调用自身。在 Haskell 中,即使是非函数也可以这样做(因为 Haskell 是惰性的)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-18
    • 1970-01-01
    • 2017-04-14
    • 1970-01-01
    • 2021-12-26
    相关资源
    最近更新 更多