Tcl-区分列表/目录和匿名进程

Tcl-区分列表/目录和匿名进程,tcl,Tcl,我编写了以下程序,它模拟了Lodash(javascript库)()中的过滤器函数。您可以用3.5基本格式调用它,如示例部分所示。对于后三个调用选项,我想去掉发送-s(速记)的要求。为了做到这一点,我需要区分匿名进程和list/dict/string 我试着查看字符串is,但没有字符串is proc。在这里研究:我发现他们建议info complete,但是在大多数情况下,无论参数类型如何,参数都会通过测试 有人知道可靠的测试方法吗?我知道我可以离开它或更改过程定义,但我正试图尽可能真实地对待L

我编写了以下程序,它模拟了Lodash(javascript库)()中的过滤器函数。您可以用3.5基本格式调用它,如示例部分所示。对于后三个调用选项,我想去掉发送-s(速记)的要求。为了做到这一点,我需要区分匿名进程和list/dict/string

我试着查看
字符串is
,但没有字符串is proc。在这里研究:我发现他们建议
info complete
,但是在大多数情况下,无论参数类型如何,参数都会通过测试

有人知道可靠的测试方法吗?我知道我可以离开它或更改过程定义,但我正试图尽可能真实地对待Lodash

示例:

set users [list \
          [dict create user barney age 36 active true] \
          [dict create user fred age 40 active false] \
        ]

 1. set result [_filter [list 1 2 3 4] {x {return true}}]
 2. set result [_filter $users -s [dict create age 36 active true]]
 3. set result [_filter $users -s [list age 36]]
 4. set result [_filter $users -s "active"]
程序代码:

proc _filter {collection predicate args} {

# They want to use shorthand syntax
if {$predicate=="-s"} {

    # They passed a list/dict
    if {[_dictIs {*}$args]} {
        set predicate {x {
            upvar args args
            set truthy 1
            dict for {k v} {*}$args {
                if {[dict get $x $k]!=$v} {
                    set truthy false
                    break
                }
            }
            return $truthy
        }}

    # They passed just an individual string
    } else {
        set predicate {x {
            upvar args args;
            if {[dict get $x $args]} {
                return true;
            }
            return false;
        }}
    }
}

# Start the result list and the index (which may not be used)
set result {}
set i -1

# For each item in collection apply the iteratee.
# Dynamically pass the correct parameters.
set paramLen [llength [lindex $predicate 0]]
foreach item $collection {
    set param [list $item]
    if {$paramLen>=2} {lappend param [incr i];}
    if {$paramLen>=3} {lappend param $collection;}
    if {[apply $predicate {*}$param]} {
        lappend result $item
    }
}
return $result
}

x{return true}
是字符串、列表、字典还是lambda术语(匿名进程的正确名称)

事实上,这可能是他们所有人;可以正确地说,它是上述任何类型的成员的值。你需要更精确、更明确地描述你的意图,而不是把它隐藏在某种类型的魔法中。通过使用像
-s
这样的选项或通过不同的主命令名,可以实现更高的精度,但这两种方法都是必需的。你不能正确和安全地做你想做的事


再深入一点…

所有Tcl值都是有效的字符串

列表具有已定义的语法,并且是字符串的正确子类型。(它们在内部的实现方式不同,但您应该忽略这些细节。)

字典的语法相当于具有偶数个元素的列表,其中偶数索引处的元素彼此都是唯一的

Lambda术语是包含两个或三个元素的列表(第三个元素是上下文名称空间的名称,如果没有,则默认为全局名称空间)。列表的第一个元素也必须是有效的列表

两元素列表符合上述所有要求。在Tcl的实际类型逻辑中,它同时满足上述所有要求。一个特定的值实例化可能有一个特定的实现表示,但这是一个暂时的东西,不能反映值的真实类型


Tcl的类型系统与许多其他语言的类型系统不同。

没错,我想知道是否有人有一种聪明的方式来表示lambda术语有这个功能,但list/dict/string没有。我看到的唯一的电位差是λlen=2或3。如果是3,我可以假设lambda,因为我实际上只接受dict或string。但是如果它的len=2,我唯一能想到的就是查看第一个组件(args),并检查它是否大于1,如果大于1,则很可能是一个lambda或一个有空格的dict键。最后,我得出了同样的结论,但我想看看是否有人更聪明。。。