【问题标题】:Need assistance understanding continuation function需要帮助理解延续功能
【发布时间】:2015-10-20 01:27:33
【问题描述】:

这是来自一个教学示例来说明 CPS 和尾递归:

fun sum [] k = k 0
  | sum (x::xs) k = sum xs (fn y=>k(x+y));

我无法理解匿名函数 fn y=>k(x+y) 如何正确总结输入列表的元素。

据我了解,匿名函数是指带有一个参数 y 的新函数,其中函数体调用带有参数 y+x 的原始函数 k

如果我调用 sum [1,2,3,4,5] (fn x=>x);,我得到 15。如果我有 sum [1,2,3,4,5] (fn x=>3x);,答案是 45。因此,sum 函数的用户必须首先了解 sum 的确切血腥细节k 的版本将产生给定列表的总和。以这种方式提供用户提供的功能的实际目的是什么?

如果我是sum 函数的编写者,我无法控制用户将为k 传递的内容。换句话说,我什至如何指定该函数将精确做什么?

【问题讨论】:

  • 我认为这是一个不好的例子:消费者不应该知道像k这样的实现细节,并且要根据函数合同获得正确的结果,他们必须传递一个身份功能。 “正确”的解决方案根本不会在 sum 签名中公开 k 参数。

标签: functional-programming sml smlnj


【解决方案1】:

因此,sum 函数的用户必须首先了解 sum 的确切细节,因为只有适当版本的 k 才会产生给定列表的总和。

没有。与往常一样,阅读文档就足够了,无需查看实现细节。您的k给出列表的确切总和 - 这就是重要的。您应该将k 理解为类似于output parameter(尽管没有突变);基本上是callback

如果我是 sum 函数的作者,我无法控制用户将为 k 传递的内容。换句话说,我什至如何指定该函数将精确做什么?

您不需要关心用户传递了什么。您只需记录该函数的作用:它使用提供的xs 列表的总和调用提供的k。它的返回值并不重要。

以这种方式提供用户提供的功能的实际目的是什么?

如果走极端,您不需要在 continuation-passing style 中返回任何值 - 您只需将其传递给回调即可。这使得调用堆栈变得多余。从另一个角度来看,每个函数都以尾调用结束,可以优化掉而不是返回。

【讨论】:

    【解决方案2】:

    我无法理解 [...] 如何正确总结输入列表的元素。

    尝试手动评估您的功能:

    sum [1,2,3] id
    sum [2,3] (fn y1=>id(1+y1))
    sum [3] (fn y2=>(fn y1=>id(1+y1))(2+y2))
    sum [] (fn y3=>(fn y2=>(fn y1=>id(1+y1))(2+y2))(3+y3))
    (fn y3=>(fn y2=>(fn y1=>id(1+y1))(2+y2))(3+y3)) 0
    (fn y2=>(fn y1=>id(1+y1))(2+y2))(3+0)
    (fn y2=>(fn y1=>id(1+y1))(2+y2)) 3
    (fn y1=>id(1+y1))(2+3)
    (fn y1=>id(1+y1)) 5
    id(1+5)
    id(6)
    6
    

    如您所见,此函数在堆内存中构建了一系列匿名函数,这些函数最终会相互调用。一个普通的递归函数会使用堆栈空间来代替。

    因此 sum 函数的用户必须首先了解 sum 的确切细节,因为只有适当版本的 k 才会产生给定列表的总和。以这种方式提供用户提供的功能的实际目的是什么?

    正如 Bergi 所写,用户不需要了解 sum 函数是如何工作的,只需了解它将延续作为参数并在其基本情况下解析它。正如 Bergi 还写道,它不必在其基本情况下评估 k。此功能的替代方法是:

    fun sum [] k = k
      | sum (x::xs) k = sum xs (fn y=>k(x+y));
    

    这里有一个应用程序,以及导出 sum 函数并将回调函数作为参数和返回值的理由是,您可以以这种方式将函数懒惰地链接在一起。例如,使用上述函数,您可以对列表进行求和;

    fun sumMany [] k = k
      | sumMany (xs::xss) k = sumMany xss (sum xs k)
    

    你可能会这样评价它

    val result = sumMany [[1,2,3],[4,5,6],[7,8,9]] (fn x=>x) 0
    

    【讨论】:

    • 谢谢!这一系列匿名函数的手动评估正是我所寻求的。对我来说,它不直观,难以阅读,也难以检查它是否产生了预期的结果。所有这些似乎都与 FP 被吹捧的相反。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-11
    • 2021-12-25
    • 1970-01-01
    • 1970-01-01
    • 2013-04-18
    相关资源
    最近更新 更多