Tcl:使用未知命令来包含点符号程序

Tcl: Using the unknown command to include dot notation procedures

Tcl 语法在其命令/参数结构的意义上非常简单和一致。有时我会想念其他语言的点符号,例如 ruby。在 ruby 你可以纠正这样的事情:

-199.abs                                                 # => 199
"ice is nice".length                                     # => 11
"ruby is cool.".index("u")                               # => 1
"Nice Day Isn't It?".downcase.split("").uniq.sort.join   # => " '?acdeinsty"

Radical Language Modification and Let unknown know中有关于如何使用未知命令修改语言的想法,例如:

proc know {cond body} {
    proc unknown {args} [string map [list @c@ $cond @b@ $body] {
        if {![catch {expr {@c@}} res] && $res} {
            return [eval {@b@}]
        }
    }][info body unknown]
}

know {[regexp {^([a-z]+)\.([a-z]+)$} [lindex $args 0] -> from to]} {
   set res {}
   while {$from<=$to} {lappend res $from; incr from}
   set res
}

# % puts [1..5]
# 1 2 3 4 5

如何修改以前的代码,以便我可以像 Ruby 示例中那样使用点符号编写命令。

您可以针对特定 操作执行此操作,但不是全部,并且存在一些句法限制。例如:

know {[regexp {^(.*)\.length$} [lindex $args 0] -> value]} {
    string length $value
}

puts [abc.length]
# ---> 3
set thevar "abc def"
puts [$thevar.length]
# ---> 7
puts ["abc def".length]
# ---> extra characters after close-quote

也就是说,该值必须仍然是句法有效的 Tcl;最后一个例子不是。您可以通过在处理程序中使用 [$value] 而不是普通的 $value 来链接 know 处理程序,前提是您有基本情况的处理程序。

know {[regexp {^(.*)\.length$} [lindex $args 0] -> value]} {
    string length [$value]
}
know {[regexp {^(.*)\.repeat\((\d+)\)$} [lindex $args 0] -> value count]} {
    string repeat [$value] $count
}
# Base case for simple words
know {[regexp {^'(.*)'$} [lindex $args 0] -> value]} {
    set value
}

puts ['abc\ def'.repeat(5).length]
# ---> 35

最终,虽然您可以做各种各样的事情,但这并不是 Tcl 设计的工作方式。它会很慢(unknown 调用机制不是优化路径)并且你会遇到限制。最好学会以正常方式做事:

puts [string length [string repeat "abc def" 5]]