我是否正确追踪了延续?

问题描述 投票:0回答:1

我正在学习延续的概念。我认为一个好主意是在用延续形式编写时跟踪典型的阶乘代码。我想知道我的理解是否正确。

代码:

fact :: Integer -> (Integer -> Integer) -> Integer
fact 0 k = k 1
fact n k = fact $ n-1 (\v -> k (n*v))

-- call: fact 5 id
-- answer: 120

这就是我跟踪代码的方式(我认为能够跟踪它是理解延续如何工作的基础):

fact 5 id --> 
fact 4 (\v -> id (5*v)) --> 
fact 3 (\v -> (\v -> id (5*v)) (4*v)) --> 
fact 2 (\v -> (\v -> (\v -> id (5*v)) (4*v)) (3*v)) --> 
fact 1 (\v -> (\v -> (\v -> (\v -> id (5*v)) (4*v)) (3*v))) (2*v)) --> 
fact 0 (\v -> (\v -> (\v -> (\v -> (\v -> id (5*v)) (4*v)) (3*v))) (2*v)) (1*v)) --> 
(\v -> (\v -> (\v -> (\v -> (\v -> id (5*v)) (4*v)) (3*v))) (2*v)) (1*v)) 1

这是应该如何追踪的还是我的基本原理错误?

PS:我知道

v
有点令人困惑,但我假设内部
v
遮蔽了外部
v

haskell continuations continuation-passing
1个回答
0
投票

是的,你的基本原理是正确的。唯一有点不正确的是你开始使用的函数。内部

v
确实遮盖了外部
v
,您可以通过打开所有 GHC 警告来发现这一点。为了使事情更容易理解,您可能需要为变量指定唯一的名称。这是我如何编写它,并使用更正后的初始函数:

fact :: Integer -> (Integer -> Integer) -> Integer
fact 0 k = k 1
fact n k = fact (n-1) (\v -> k (n*v))

-- call: fact 5 id
main :: IO ()
main = do
    print $ fact 5 id
    print $ fact 4 (\v0 -> id (5*v0))
    print $ fact 4 (\v0 -> 5*v0)
    print $ fact 4 (\v0 -> 5*v0)
    print $ fact 3 (\v1 -> (\v0 -> 5*v0) (4*v1))
    print $ fact 2 (\v2 -> (\v1 -> (\v0 -> 5*v0) (4*v1)) (3*v2))
    print $ fact 1 (\v3 -> (\v2 -> (\v1 -> (\v0 -> 5*v0) (4*v1)) (3*v2)) (2*v3))
    print $ fact 0 (\v4 -> (\v3 -> (\v2 -> (\v1 -> (\v0 -> 5*v0) (4*v1)) (3*v2)) (2*v3)) (1*v4))
    print $ (\v4 -> (\v3 -> (\v2 -> (\v1 -> (\v0 -> 5*v0) (4*v1)) (3*v2)) (2*v3)) (1*v4)) 1
最新问题
© www.soinside.com 2019 - 2024. All rights reserved.