我正在学习延续的概念。我认为一个好主意是追踪用延续形式编写的典型阶乘代码。我想知道我的理解是否正确。
代码:
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
这是应该如何追踪吗,还是我的基本概念错了?
附言:我理解v
s 有点令人困惑,但我假设内部v
遮蔽了外部v
?
是的,你掌握了基本知识。唯一稍微不正确的是你开始使用的函数。 inner
v
确实遮蔽了 outerv
,你可以通过打开所有 GHC 警告来发现这一点。为了使事情更容易理解,你可能希望为变量赋予唯一的名称。下面是我使用更正后的初始函数编写的方法: