Tcl 现代方法:tailcall

Ma Kai posted @ Sep 21, 2014 09:30:49 PM in 编程 with tags tcl tcl 现代方法 , 2144 阅读

Tailcall 是 Tcl 8.6 引入的新功能。功能如其名,本来是用来实现尾调用的。

proc factorial {n {accum 1}} {
    if {$n < 2} {
        return $accum
    }
    tailcall factorial [expr {$n - 1}] [expr {$accum * $n}]
}

tailcall 有个实现细节:替换掉当前的栈。于是带来了一些有趣的妙用。

proc min {a b} {
    if {$a > $b} {
        tailcall max $b $a
    }
    return $a
}

这个 min 函数故意绕弯,对于最坏的情况会导致两个 if 检查,但是对于一些比较复杂的函数,就让人麻烦了。比如说

# 
# Make sure b is greater than a!
# 
proc ComplexCalculation {a b} {
    if {$a > $b} {
        tailcall ComplexCalculation $b $a
    }
    # Much
    # Code
    # Omitted
}

尽管我们在文档里面写了要求 b 大于 a,但是有的情况下我们不知道哪个大于哪个呀!而且有的时候脑袋一懵写反了就糟糕了。在没有 tailcall 之前,我们必须得自己判断哪个大于哪个,麻烦死了,这点工作还是隐藏起来好了(从代码重用的角度看也应该这么做)。于是加上简简单单三行代码,就可以轻松省下许许多多的判断。

另外一个用处,被莫名其妙地用来实现 do ... while 控制结构……(出处,这段小小的代码也被我用到了记忆大师里面。)

proc do {code while cond} {
    tailcall try $code\n[list $while $cond $code]
}

因为 tailcall 的一个奇妙的实现细节,我们就多了这么多乐趣!我曾经在 Tcl Chatroom 里面「抱怨」说 tailcall 不应该叫 tailcall,应该叫 replaceCurrentStackFrame。这时候有个人说,尾调用 tailcall 的意思就是在一个栈的尾部调用嘛!恍然大悟。


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter