Tcl - 区分list / dict和匿名proc

时间:2017-10-19 11:09:09

标签: tcl

我编写了以下proc,它模拟了Lodash(javascript库)(https://lodash.com/docs/4.17.4#filter)中的过滤功能。您可以在3.5基本格式中调用它,如示例部分所示。对于后三种调用选项,我想摆脱以-s(简写)发送的要求。为了做到这一点,我需要区分匿名proc和list / dict / string。

我试着查看string is,但是没有字符串是proc。在此处进行研究:http://wiki.tcl.tk/10166我发现他们推荐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 Code:

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
}

1 个答案:

答案 0 :(得分:2)

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

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

更深入一点......

所有Tcl值都作为字符串有效。

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

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

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

两元素列表符合上述所有要求。在Tcl的实际类型逻辑中,它同时是 all 。值的特定实例化可能在封面下具有特定的实现表示,但这是一个不能反映值的真实类型的瞬态事物。

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