Tcl: Как вывести операторы для заполнения аргументов по умолчанию во время вызова - PullRequest
3 голосов
/ 20 марта 2012

Как вы предоставляете аргументы по умолчанию для процедуры Tcl, которые оцениваются во время вызова?

Вот пример того, что я пробовал:

> tclsh
% proc test { {def [expr 4 + 3]} } { puts $def }
too many fields in argument specifier "def [expr 4 + 3]"
% proc test { {def {[expr 4 + 3]}} } {puts $def}
% test
[expr 4 + 3]
% test 5
5
% proc test { {def {[expr 4 + 3]}} } {puts [$def]}
% test
invalid command name "[expr 4 + 3]"
% proc test { {def {[expr 4 + 3]}} } {puts [eval $def]}
% test
invalid command name "7"

Пример только для упрощения кода. Конечно, в этом простом примере можно просто использовать {def 7}, чтобы установить значение по умолчанию для процедуры.

Однако цель состоит в том, чтобы иметь возможность вызывать более сложную функцию, которая выдает хорошее значение по умолчанию при вызове процедуры test. Значения по умолчанию могут отличаться.

Мое текущее решение состоит в том, чтобы по умолчанию использовать пустую строку и проверить, что:

% proc test { {def {}} }  {  if {$def == {}} { set def [expr 4 + 3] } ; puts $def }
% test
7
% test 5
5

Однако я считаю это недостаточно элегантным: должен быть способ поместить объявления в том месте, в котором они находятся: в заголовке.

Также, возможно, пустая строка может быть совершенно точным значением, заданным вызывающей стороной, которое не должно заменяться вызовом по умолчанию.

Другим обходным решением может быть просто использовать args в качестве параметра, а затем проверить его. Но это обеспечивает еще менее явный декларативный стиль.

Есть идеи, как я могу включить eval в декларативный заголовок proc?

(я нахожусь на Tcl8.4 без возможности обновления из-за использования в среде коммерческих инструментов. Но ради этого сайта я бы также рекомендовал ответы для более современных версий tcl)

Ответы [ 2 ]

2 голосов
/ 20 марта 2012

Если вы знаете , что вы будете передавать только цифры, вы можете сделать это:

proc test {{def {4+3}}} {
    puts [expr $def]
}

Но это небезопасно , если вы обрабатываете общие аргументы. (Если бы кому-то удалось передать «[exit]», вы бы заметили!) Безопасное обращение с требует более сложной обработки. Если вы можете использовать значение часового типа, например, пустую строку:

proc test {{def ""}} {
    if {[string equal $def ""]} {set def [expr 4+3]}
    puts $def
}

Если у вас нет такого дозорного, вы должны либо использовать спец. args и выполнять всю работу самостоятельно, либо посмотреть длину списка, возвращаемого info level 0.

Вы можете обернуть proc своим собственным кодом, чтобы все было проще.

proc xproc {name arguments body} {
    for {set n [llength $arguments]} {[incr n -1] >= 0} {} {
        if {[llength [lindex $arguments $n]] > 1} {
            foreach {v def} [lindex $arguments $n] break
            set body "if {\[llength \[info level 0\]\] <= $n+1} {set $v \[expr $def\]};$body"
        }
    }
    proc $name $arguments $body
}

После этого вы можете написать:

xproc test {{def {4+3}}} {
    puts $def
}
2 голосов
/ 20 марта 2012

Как насчет этого (который немного отличается от ваших попыток):

% proc test {{def {[expr 4+3]}}} {eval puts "$def"}
% test
7
% test 5
5
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...