Haskell:在连续传递风格中完全定义阶乘的问题

发布于 2024-10-13 20:49:19 字数 358 浏览 9 评论 0原文

我一直试图在一大堆内容中理解函数式编程、Haskell 和延续传递风格,而我的结构化/OOP 背景给我带来了困难。

根据 this 我理解以下应该是 CPS 风格中阶乘的正确定义:

factorial n = fact n id where id = \x -> x
    fact 0 cont = cont n
    fact (n+1) cont = fact n * (n + 1)

但我不确定最后的“* (n + 1)”部分 - 这是正确的吗?

I've been trying to understad Functional Programming, Haskell and Continuation Passing Style in one big blob and my structured/OOP background is giving me a hard time.

According to this I understand the following should be a correct definition of factorial in CPS-style:

factorial n = fact n id where id = \x -> x
    fact 0 cont = cont n
    fact (n+1) cont = fact n * (n + 1)

but I'm not sure about the "* (n + 1)" part at the end - is that correct?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

冰魂雪魄 2024-10-20 20:49:20

它不太正确(并且不适合我编译);值n+1是正确的,但它的使用方式不正确。也许您想使用操作符部分?

factorial n' = fact n' id
 where
  id = \x -> x
  fact 0 cont = cont 1
  fact (n+1) cont = fact n (cont . (* (n+1)))

这与下面的内容相同(但更迟钝),

factorial n' = fact n' id
 where
  id = \x -> x
  fact 0 cont = cont 1
  fact (n+1) cont = fact n (\ret -> cont (ret * (n+1)) )

我将在这里更改一些内容。首先,id 是一个标准函数,因此您不需要重新定义它。其次,这些示例使用“n+k 模式”,IIRC 在 GHC 中默认不再可用。您可以使用普通模式变量来代替“n+k 模式”。请注意,我使用 1 作为基本情况;如果您从 n 开始倒数,并且应该在计算中的每个步骤应用延续函数(您已将其从归纳步骤中删除),那么这更容易推理。记住这些,你就可以写出

factorial n' = fact n' id
 where
  fact 0 cont = cont 1
  fact n cont = fact (n-1) (cont . (* n))

我认为或多或少地道的内容。

编辑:我个人不喜欢 n+k 模式,但我想我需要花点时间来解释它们。我发现如果你考虑带有基本情况和归纳步骤的数学归纳法,就更容易理解。基本情况是事实 0 ...。然后,您可以从基本步骤开始定义其他值:“对于任何fact n k,通过此关系确定fact (n+1) k”。这与我对正常模式变量的看法不同,即自上而下而不是像这里一样自下而上,但我认为它解释了动机以及为什么有些人喜欢这种风格。

我不喜欢 n+k 模式的原因只是因为我发现定义更混乱,但是 YMMV。

It's not quite correct (and doesn't compile for me); the value n+1 is right but it isn't used in quite the correct way. Maybe you meant to use an operator section?

factorial n' = fact n' id
 where
  id = \x -> x
  fact 0 cont = cont 1
  fact (n+1) cont = fact n (cont . (* (n+1)))

This is identical to (but more obtuse than) the following

factorial n' = fact n' id
 where
  id = \x -> x
  fact 0 cont = cont 1
  fact (n+1) cont = fact n (\ret -> cont (ret * (n+1)) )

There are a few things I would change here. First, id is a standard function so you don't need to redefine it. Secondly, these examples use "n+k patterns", which IIRC are no longer available by default in GHC. Instead of an "n+k pattern", you can use a normal pattern variable. Note that I used 1 for the base case; this is simpler to reason about if you're counting down from n, and the continuation function should be applied at each step within the computation (you'd dropped it from the induction step). With these in mind, you can write

factorial n' = fact n' id
 where
  fact 0 cont = cont 1
  fact n cont = fact (n-1) (cont . (* n))

which I would consider more or less idiomatic.

Edit: I personally don't like n+k patterns, but I thought I'd take a bit of time to explain them. I find it easier to follow if you think of mathematical induction with a base case and an induction step. The base case is fact 0 .... You then define the other values by proceeding from the base step: "for any fact n k, determine fact (n+1) k by this relation." This is different from how I think of normal pattern variables, that is top-down instead of bottom-up as here, but I think it explains the motivation and why some people like the style.

The reason I don't like n+k patterns is simply because I find the definitions more cluttered, but YMMV.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文