8
28
2014
1

Tcl 实现伪闭包

proc lambda {vars args body} {
    set exvars [lmap var $vars {
        upvar $var localvar
        list $var $localvar
    }]
    lappend args {*}$exvars
    list apply [list $args $body]
}

简单地用 apply 实现一个“伪闭包”。其中 {*} 需要 Tcl 8.5,[lmap] 需要 8.6。

所谓“伪”是因为这个函数没法真正地持有变量引用,只能复制一下。有点像是缩水版的 C++ 闭包frown。虽说只是复制,但还是十分好用,因为 Tcl 在核心层面的“复制”使用的是引用计数,而且若原函数退出,也不会影响到匿名函数里面的变量,毕竟 Tcl 是没有垃圾收集的,这样做凑合能算不错吧。

有个比较遗憾的限制是,因为我比较懒,用“可选参数”实现了变量复制,所以如果参数列表有 args 且使用了外部变量,就会退化到普通的变量(正如 lambda 自身的 args)。

这个函数基本用法是这样的:

set x 100
{*}[lambda x {a b} {
    puts "x = $x\na=$a\nb=$b"
}] 10 20

自然,你也可以给 lambda 返回的“闭包”一个名字:

set x 100
set closure [lambda x {a b} {
    puts "x = $x\na=$a\nb=$b"
}]
{*}$closure 10 20

实际上,这玩意在 Tk 上最好用:

proc foo {} {
    set msg "使用 lambda 辅助函数十分方便吧!"
    ttk::button .b -text 点我 -command [lambda msg {} {
        tk_messageBox -message $msg
    }]
    pack .b
}
foo

一般情况下,Tk 直接这样写是不行的,因为 -command 是在全局命名空间里执行的:

proc foo {} {
    set msg "这是不行的!"
    ttk::button .b -text 点我 -command {
        tk_messageBox -message $msg
    }
    pack .b
}
foo

会报错找不到 msg 变量。

如果你比较熟悉 Tcl,可能想问为什么不用 subst,像下面这样:

proc foo {} {
    set msg "hello tcl!"
    ttk::button .b -text 点我 -command [subst -nocommands {
        tk_messageBox -message $msg
    }]
    pack .b
}
foo

我开始也以为可以,但遗憾的是,不行。因为 Tk 使用 eval 处理 command,在上面的例子中,eval 会把原来好好的命令曲解成这样:

tk_messageBox -message hello tcl!
# 也就是
tk_messageBox -message {*}"hello tcl!"

这是因为 eval 使用了 concat,而 concat 会把列表展开一层,正如 {*} 一样:

concat {{1 2} 3} 4
# → {1 2} 3 4

eval 的“展开”特性在少数情况下有用,大部分情况下 {*} 就可以替代 eval,在此不赘述。

Category: 编程 | Tags: tcl | Read Count: 2172
BIETS 1st & 2nd Year 说:
Aug 17, 2022 10:23:28 PM

BIETS 1st & 2nd Year Exams Dates 2023, TS Intermediate Question Paper 2023, The Telangana Secondary and Higher Secondary Education Board BIETS will release the Question Paper and New Question Paper for the TS Intermediate First and Second Year Examination in 2023. The BSE Annual Examination 2023 was held in November by the Telangana Secondary and Higher Secondary Education Board BSETS. BIETS 1st & 2nd Year Model Paper 2023 For effective preparation, all candidates who have enrolled for the BIETS First and Second Year Examinations 2023 must download the Telangana Inter Question Paper 2023. For the intermediate test in 2023, which will be held in March, more than six lakh individuals will apply.


登录 *


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

Powered by Chito | Hosted at is-Programmer | Theme: Aeros 2.0 by TheBuckmaker.com