Почему Tcl допускает имена процедур с пробелами, но не параметры с пробелами? - PullRequest
2 голосов
/ 02 апреля 2019

Ради интереса я написал следующий фрагмент кода:

proc "bake a cake" {"number_of_people" {number_of_children}} {
    set fmt "Take %d pounds of flour and %d bags of marshmallows."
    puts [format $fmt "${number_of_people}" ${number_of_children}]
    puts "Put them into the oven and hope for the best."
}

"bake a cake" 3 3
{bake a cake} 5 0

Мне показалось забавным, что имена процедур могут содержать пробелы.Я думал, что объединение этого с практически неиспользуемыми аргументами позволит сделать программы Tcl очень похожими на разговорный естественный язык, аналогично Smalltalk с его bakeACake forPeople: 3 andChildren: 3, только без странного двоеточия, нарушающего предложения и неестественный порядок слов.

Для дальнейшего изучения этой идеи я попробовал ту же схему для параметров процедуры, заменив каждый _ простым пробелом.Tclsh8.6 это не понравилось:

too many fields in argument specifier "number of people"
    (creating proc "bake a cake")
    invoked from within
"proc "bake a cake" {"number of people" {number of children}} {
        set fmt "Take %d pounds of flour and %d bags of marshmallows."
        puts [format $fmt "${n..."
    (file "bake.tcl" line 1)

Это подняло следующие вопросы:

  • Есть ли убедительная причина того, почему имена процедур могут содержать пробелы, но имена параметровне может?
  • Это просто деталь реализации proc?
  • Можно ли написать spaceproc, который разрешает этот синтаксический вариант?

1 Ответ

3 голосов
/ 02 апреля 2019

Внимательно прочитайте документацию proc: каждый из аргументов в списке аргументов сам является списком, который должен иметь 1 или 2 элемента: обязательное имя аргумента и необязательное значение по умолчанию,"number of people" имеет слишком много элементов.Вы можете получить то, что хотите, с помощью еще одного слоя фигурных скобок:

% proc "bake a cake" {{"for people"} {"and children"}} {
    puts "baking a cake for [set {for people}] people and [set {and children}] children"
}
% "bake a cake" 1 2
baking a cake for 1 people and 2 children
% "bake a cake"
wrong # args: should be "{bake a cake} {for people} {and children}"

Я не вижу выгоды от проведения этого эксперимента: неуклюжие имена переменных исключают синтаксический сахар $.

Обратите внимание, что не так сложно получить код, похожий на Smalltalk

% proc bakeACake {forPeople: nPeople andChildren: nChildren} {
    if {[set forPeople:] ne "forPeople:" || [set andChildren:] ne "andChildren:"} {
        error {should be "bakeACake forPeople: nPeople andChildren: nChildren"}
    }
    puts "baking a cake for $nPeople people and $nChildren children"
}
% bakeACake
wrong # args: should be "bakeACake forPeople: nPeople andChildren: nChildren"
% bakeACake foo 1 bar 2
should be "bakeACake forPeople: nPeople andChildren: nChildren"
% bakeACake forPeople: 3 andChildren: 4
baking a cake for 3 people and 4 children

Хотя в отличие от Smalltalk, у вас не может быть других команд, начинающихся с "bakeACake" (если только вы не копаетесь в "ансамблях пространства имен")

...