summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorweirdvic <56339132+weirdvic@users.noreply.github.com>2023-04-12 19:51:05 +0300
committerweirdvic <56339132+weirdvic@users.noreply.github.com>2023-04-12 19:51:05 +0300
commit4e88b2cdba021d9be72d8e64793d6cd086e8710b (patch)
tree892e490fceed8c8463eeb2a8b6666298112365db
parentfbaa905e23f26d20b37a3886dd8e07cd6edb8680 (diff)
Added russian translation for Tcl page
-rw-r--r--ru-ru/tcl-ru.html.markdown589
1 files changed, 589 insertions, 0 deletions
diff --git a/ru-ru/tcl-ru.html.markdown b/ru-ru/tcl-ru.html.markdown
new file mode 100644
index 00000000..723efe30
--- /dev/null
+++ b/ru-ru/tcl-ru.html.markdown
@@ -0,0 +1,589 @@
+---
+language: Tcl
+contributors:
+ - ["Poor Yorick", "https://pooryorick.com/"]
+translators:
+ - ["Viktor Sokhranov", "https://github.com/weirdvic"]
+filename: learntcl.tcl
+---
+
+Tcl был создан [Джоном Оустерхаутом](https://ru.wikipedia.org/wiki/Оустерхаут,_Джон)
+в качестве скриптового языка в своих инструментах проектирования электрических цепей.
+В 1997 году за разработку языка Tcl автор получил [ACM](https://ru.wikipedia.org/wiki/ACM)
+ Software System Award. Tcl может использоваться и как встраиваемый скриптовый язык,
+и как язык программирования общего назначения. Кроме того, он может быть использован как
+библиотека в программах на C, даже в случаях когда не требуется написание скриптов,
+поскольку Tcl может предоставить программе на C различные типы данных, такие как
+динамические строки, списки и хэш-таблицы. Также с помощью этой библиотеки возможно
+использовать форматирование строк, операции с файловой системой, работу с кодировками и
+динамически загружаемые библиотеки. К другим особенностям Tcl относятся:
+
+* Удобный кроссплатформенный API для работы с сетью
+
+* Поддержка виртуальной файловой системы(VFS)
+
+* Стекируемые каналы ввода-вывода
+
+* Асинхронность в ядре языка
+
+* Поддержка корутин
+
+* Простая и надёжная модель потоков выполнения
+
+Tcl имеет много общего с Lisp, но в отличие от списков, в Tcl "валютой" языка
+являются строки. Все значения являются строками. Список в Tcl это просто строка в
+определённом формате, а тело процедуры(скрипт) это ещё одна строка, а не блок.
+С целью увеличения производительности, интерпретатор Tcl использует кэшированные
+внутренние представления различных типов данных. Например, рутины(routines), работающие
+со списками, фактически используют внутреннее представление списков, а интерпретатор
+Tcl обновляет строковое представление в том случае если оно используется в скрипте.
+В Tcl используется подход copy-on-write, позволяющий оперировать большими объёмами
+данных без дополнительного оверхеда. Процедуры в Tcl автоматически компилируются
+в байткод, кроме случаев когда в процедуре используются динамические рутины, такие
+как "uplevel", "upvar" и "trace"
+
+Программировать на Tcl приятно. Его находят привлекательным хакеры, которым интересны
+Lisp, Forth или Smalltalk, а также инженеры и учёные, которым просто необходим
+гибкий инструмент для выполнения их задач. В Tcl языковые конструкции, включая
+циклы и математические операторы, представлены в виде изменяемых рутин, в отличие
+от других языков программирования, где они закреплены в синтаксисе, что позволяет
+синтаксису Tcl не мешать работать с предметной областью проекта. Синтаксис Tcl в этом
+смысле даже более минималистичен чем у Lisp.
+
+
+
+```tcl
+#! /bin/env tclsh
+
+###############################################################################
+## 1. Рекомендации
+###############################################################################
+
+# Tcl это не shell или C! Этот момент требует уточнения, поскольку привычки
+# написания shell-скриптов почти работают в Tcl и часто люди начинают
+# изучать Tcl со знанием синтаксиса других языков. Поначалу это работает, но
+# когда скрипты становятся сложнее, наступает фрустрация.
+
+# Фигурные скобки {} в Tcl используются не для построения блоков кода или
+# списков, а как механизм экранирования(quoting) для кода. Фактически в Tcl
+# нет ни списков, ни блоков кода. Фигурные скобки использутся для
+# экранирования специальных символов и потому подходят для представления
+# тела процедур и строк, которые должны интерпретироваться как списки.
+
+
+###############################################################################
+## 2. Синтаксис
+###############################################################################
+
+# Скрипт состоит из команд, разделённых символами перевода строки или символами
+# точки с запятой. Каждая команда представляет собой вызов рутины. Первое слово
+# это имя вызываемой рутины, а последующие слова это аргументы. Слова разделены
+# пробелами. Так как каждый аргумент это слово в команде, он является строкой и
+# может быть неэкранирован:
+set part1 Sal
+set part2 ut; set part3 ations
+
+
+# символ доллара используется для подставления значения переменных:
+set greeting $part1$part2$part3
+
+
+# Когда "set" получает только имя переменной, возвращается значение переменной:
+set part3 ;# Возвращает значение переменной
+
+
+# Содержимое квадратных скобок заменяется на результат выполнения:
+set greeting $part1$part2[set part3]
+
+
+# Встроенный таким образов скрипт может состоять из нескольких команд, но
+# результат подстановки определяется последней командой:
+set greeting $greeting[
+ incr i
+ incr i
+ incr i
+]
+puts $greeting ;# Выведет "Salutations3"
+
+# Каждое слово в команде является строкой, включая имя рутины, поэтому
+# подстановки могут быть использованы и таким образом:
+set action pu
+
+# следующие команды эквивалентны:
+puts $greeting
+${action}ts $greeting
+[set action]ts $greeting
+
+
+# Обратный слэш экранирует специальные символы:
+set amount \$16.42
+
+
+# и он же используется для ввода специальных символов:
+puts lots\nof\n\n\n\n\n\nnewlines
+
+
+# Слово в фигурных скобках никак не интерпретируется и в нём не работают
+# никакие подстановки, за исключением экранирования закрывающей скобки:
+set somevar {
+ Это литерал знака $, а это \} экранированная закрывающая скобка
+}
+
+
+# В слове внутри двойных кавычек, пробельные символы теряют своё
+# специальное значение:
+set name Neo
+set greeting "Hello, $name"
+
+
+# Имя переменной может быть любой строкой:
+set {first name} New
+
+
+# Фигурные скобки используются для доступа к переменным с составными именами:
+set greeting "Hello, ${first name}"
+
+
+# "set" всегда можно использовать вместо подстановки переменной:
+set greeting "Hello, [set {first name}]"
+
+
+# Чтобы "распаковать" список в команду используется оператор расширения "{*}"
+# Эти две команды эквивалентны:
+set name Neo
+set {*}{name Neo}
+
+
+# Массив это особая переменная, являющаяся контейнером для других переменных.
+set person(name) Neo
+set person(destiny) {The One}
+set greeting "Hello, $person(name)"
+
+
+# "variable" может быть использована для объявления или установки переменных.
+# В отличие от "set", которая использует глобальное и локальное пространство
+# имён, "variable" работает только с локальным пространством:
+variable name New
+
+
+# "namespace eval" создаёт новое пространство имён, если его не существует.
+# Пространство имён может содержать рутины и переменные:
+namespace eval people {
+ namespace eval person1 {
+ variable name Neo
+ }
+}
+
+
+# Двумя или более двоеточиями в именах переменных отделяется название
+# пространства имён:
+namespace eval people {
+ set greeting "Hello $person1::name"
+}
+
+# Два или более двоеточия также отделяют название пространства имён
+# в имени рутины:
+proc people::person1::speak {} {
+ puts {I am The One.}
+}
+
+# Полные(fully-qualified) имена начинаются с двух двоеточий:
+set greeting "Hello $::people::person1::name"
+
+
+
+###############################################################################
+## 3. Больше никакого синтаксиса
+###############################################################################
+
+# Все остальные функции реализованы посредством рутин. С этого момента и далее
+# больше нет нового синтаксиса. Всё остальное что можно изучить о Tcl это
+# поведение отдельных рутин и какие значения они присваивают своим аргументам.
+
+
+
+###############################################################################
+## 4. Переменные и пространства имён
+###############################################################################
+
+# Каждая переменная и рутина связанс с пространством имён.
+
+# Чтобы получить интерпретатор, которые не может сделать ничего, достаточно
+# удалить глобальное пространство имён. Особой пользы в этом нет, но это хорошо
+# иллюстрирует природу Tcl. Фактически имя глобального пространства имён это
+# пустая строка, но единственный способ представить её -- в виде полного имени:
+proc delete_global_namespace {} {
+ namespace delete ::
+}
+
+# Поскольку "set" всегда учитывает и глобальное, и текущее пространства имён,
+# более безопасно использовать "variable" чтобы объявить новую переменную или
+# задать значение переменной. Если переменная с именем "name" уже существует
+# в глобальном пространстве имён, использование "set" задаст значение
+# глобальной переменной, тогда как "variable" работает только с текущим
+# пространством имён.
+
+namespace eval people {
+ namespace eval person1 {
+ variable name Neo
+ }
+}
+
+# После объявления переменной в пространстве имён, [set] видит её, а не
+# одноимённую переменную в глобальном пространстве имён:
+
+namespace eval people {
+ namespace eval person1 {
+ variable name
+ set name Neo
+ }
+}
+
+# Но если "set" приходится создать новую переменную, он всегда делает это
+# с учётом текущего пространства имён:
+unset name
+namespace eval people {
+ namespace eval person1 {
+ set name neo
+ }
+
+}
+set people::person1::name
+
+
+# Абсолютное имя всегда начинается с имени глобального пространства имён, то
+# есть с пустой строки, за которой следует два двоеточия:
+set ::people::person1::name Neo
+
+
+# В пределах процедуры "variable" связывает перменную в текущем пространстве
+# имён с локальной областью видимости:
+namespace eval people::person1 {
+ proc fly {} {
+ variable name
+ puts "$name is flying!"
+ }
+}
+
+
+
+
+###############################################################################
+## 5. Встроенные рутины
+###############################################################################
+
+# Математические операции можно выполнять при помощи "expr":
+set a 3
+set b 4
+set c [expr {$a + $b}]
+
+# Поскольку "expr" самостоятельно занимается подстановкой значений переменных,
+# математическое выражение нужно оборачивать в фигурные скобки чтобы отключить
+# подстановку значений переменных интерпретатором Tcl.
+# Подробнее об этом можно прочесть здесь:
+# "https://wiki.tcl-lang.org/page/Brace+your+expr-essions"
+
+
+# "expr" выполняет подстановку переменных и результатов команд:
+set c [expr {$a + [set b]}]
+
+
+# "expr" предоставляет разные математические функции:
+set c [expr {pow($a,$b)}]
+
+
+# Математические операторы сами по себе доступны в виде рутин в
+# пространстве имён ::tcl::mathop
+::tcl::mathop::+ 5 3
+
+# Рутины могут быть импортированы из других пространств имён:
+namespace import ::tcl::mathop::+
+set result [+ 5 3]
+
+
+# Не числовые значения должны быть квотированы. Такие операторы как "eq"
+# Могут быть использованы чтобы провести строковое сравнение:
+set name Neo
+expr {{Bob} eq $name}
+
+# Общие операторы сравнения тоже работают со строками если числовое значение
+# операнда недоступно:
+expr {{Bob} == $name}
+
+
+# "proc" создаёт новые рутины:
+proc greet name {
+ return "Hello, $name!"
+}
+
+# можно указать несколько параметров:
+proc greet {greeting name} {
+ return "$greeting, $name!"
+}
+
+
+# Как было отмечено ранее, фигурные скобки не обозначают блок кода.
+# Любое значение, даже третий аргумент "proc" является строкой.
+# Предыдущая команда может быть переписана без использования фигурных скобок:
+
+# As noted earlier, braces do not construct a code block. Every value, even
+# the third argument to "proc", is a string. The previous command
+# can be rewritten using no braces:
+proc greet greeting\ name return\ \"\$greeting,\ \$name!\"
+
+
+
+# Если последний параметр называется "args", все дополнительные аргументы,
+# переданные рутине, собираются в список и передаются как "args":
+proc fold {cmd first args} {
+ foreach arg $args {
+ set first [$cmd $first $arg]
+ }
+ return $first
+}
+fold ::tcl::mathop::* 5 3 3 ;# -> 45
+
+
+# Условное выполнение тоже реализовано как рутина:
+if {3 > 4} {
+ puts {This will never happen}
+} elseif {4 > 4} {
+ puts {This will also never happen}
+} else {
+ puts {This will always happen}
+}
+
+
+# Циклы реализованы как рутины. Первый и третий аргументы для "for"
+# обрабатываются как скрипты, а второй аргумент как выражение:
+set res 0
+for {set i 0} {$i < 10} {incr i} {
+ set res [expr {$res + $i}]
+}
+unset res
+
+
+# Первый аргумент для "while" тоже обрабатывается как выражение:
+set i 0
+while {$i < 10} {
+ incr i 2
+}
+
+
+# Список это строка, а элементы списка разделены пробелами:
+set amounts 10\ 33\ 18
+set amount [lindex $amounts 1]
+
+# Если элемент списка содержит пробел, его надо экранировать:
+set inventory {"item 1" item\ 2 {item 3}}
+
+
+# Хорошая практика использовать списковые рутины для обработки списков:
+lappend inventory {item 1} {item 2} {item 3}
+
+
+# Фигурные скобки и бэкслеш могут быть использованы чтобы хранить более
+# комплексные структуры внутри списков. Список выглядит как скрипт, за
+# исключением того, что перевод строки и точка с запятой теряют своё
+# специальное значение, а также не производится подстановка значений.
+# Эта особенность Tcl называется гомоиконичность
+# https://ru.wikipedia.org/wiki/Гомоиконичность
+# В приведённом списке есть три элемента:
+set values {
+
+ one\ two
+
+ {three four}
+
+ five\{six
+
+}
+
+
+# Поскольку как и все значения, список является строкой, строковые
+# операции могут выполняться и над списком, с риском повреждения:
+set values {one two three four}
+set values [string map {two \{} $values] ;# $values больше не \
+ правильно отформатированный список
+
+
+# Безопасный способ работать со списками — использовать "list" рутины:
+set values [list one \{ three four]
+lappend values { } ;# добавить символ пробела как элемент в список
+
+
+# Использование "eval" для вычисления значения скрипта:
+eval {
+ set name Neo
+ set greeting "Hello, $name"
+}
+
+
+# Список всегда можно передать в "eval" как скрипт, содержащий одну команду:
+eval {set name Neo}
+eval [list set greeting "Hello, $name"]
+
+
+# Следовательно, когда используется "eval", используйте "list" чтобы собрать
+# необходимую команду:
+set command {set name}
+lappend command {Archibald Sorbisol}
+eval $command
+
+
+# Частая ошибка: не использовать списковые функции для построения команды:
+set command {set name}
+append command { Archibald Sorbisol}
+try {
+ eval $command ;# Здесь будет ошибка, превышено количество аргументов \
+ к "set" в {set name Archibald Sorbisol}
+} on error {result eoptions} {
+ puts [list {received an error} $result]
+}
+
+# Эта ошибка запросто может произойти с "subst":
+
+set replacement {Archibald Sorbisol}
+set command {set name $replacement}
+set command [subst $command]
+try {
+ eval $command ;# Та же ошибка, лишние аргументы к \
+ {set name Archibald Sorbisol}
+} trap {TCL WRONGARGS} {result options} {
+ puts [list {received another error} $result]
+}
+
+
+# "list" корректно форматирует значение для подстановки:
+set replacement [list {Archibald Sorbisol}]
+set command {set name $replacement}
+set command [subst $command]
+eval $command
+
+
+# "list" обычно используется для форматирования значений для подстановки в
+# скрипты, вот несколько примеров:
+
+
+# "apply" вычисляет список из двух элементов как рутину:
+set cmd {{greeting name} {
+ return "$greeting, $name!"
+}}
+apply $cmd Whaddup Neo
+
+# Третий элемент может быть использован для указания пространства имён рутины:
+set cmd [list {greeting name} {
+ return "$greeting, $name!"
+} [namespace current]]
+apply $cmd Whaddup Neo
+
+
+# "uplevel" вычисляет скрипт на уровень выше в списке вызовов:
+proc greet {} {
+ uplevel {puts "$greeting, $name"}
+}
+
+proc set_double {varname value} {
+ if {[string is double $value]} {
+ uplevel [list variable $varname $value]
+ } else {
+ error [list {not a double} $value]
+ }
+}
+
+
+# "upvar" связывает переменную на текущем уровне вызовов с переменной на
+# более высоком уровне:
+proc set_double {varname value} {
+ if {[string is double $value]} {
+ upvar 1 $varname var
+ set var $value
+ } else {
+ error [list {not a double} $value]
+ }
+}
+
+
+# Избавляемся от встроенной рутины "while" и используем "proc" чтобы написать
+# свою версию:
+rename ::while {}
+# обработка оставлена как упражнение:
+proc while {condition script} {
+ if {[uplevel 1 [list expr $condition]]} {
+ uplevel 1 $script
+ tailcall [namespace which while] $condition $script
+ }
+}
+
+
+# "coroutine" создаёт новый стек вызовов, новую рутину для входа в этот стек
+# и вызывает эту рутину. "yield" приостанавливает вычисления в этом стеке и
+# возвращает управление вызывавшему стеку:
+proc countdown count {
+ # отправить что-нибудь обратно создателю корутины, фактически
+ # останавливая стек вызовов на время.
+ yield [info coroutine]
+
+ while {$count > 1} {
+ yield [incr count -1]
+ }
+ return 0
+}
+coroutine countdown1 countdown 3
+coroutine countdown2 countdown 5
+puts [countdown1] ;# -> 2
+puts [countdown2] ;# -> 4
+puts [countdown1] ;# -> 1
+puts [countdown1] ;# -> 0
+catch {
+ puts [coundown1] ;# -> invalid command name "countdown1"
+} cres copts
+puts $cres
+puts [countdown2] ;# -> 3
+
+
+# Стеки корутин могут передавать контроль друг другу:
+
+proc pass {whom args} {
+ return [yieldto $whom {*}$args]
+}
+
+coroutine a apply {{} {
+ yield
+ set result [pass b {please pass the salt}]
+ puts [list got the $result]
+ set result [pass b {please pass the pepper}]
+ puts [list got the $result]
+}}
+
+coroutine b apply {{} {
+ set request [yield]
+ while 1 {
+ set response [pass c $request]
+ puts [list [info coroutine] is now yielding]
+ set request [pass a $response]
+ }
+}}
+
+coroutine c apply {{} {
+ set request [yield]
+ while 1 {
+ if {[string match *salt* $request]} {
+ set request [pass b salt]
+ } else {
+ set request [pass b huh?]
+ }
+ }
+}}
+
+
+
+```
+
+## Ссылки
+
+[Официальная документация Tcl](https://www.tcl-lang.org)
+
+[Tcl Wiki](https://wiki.tcl-lang.org)
+
+[Tcl на Reddit](http://www.reddit.com/r/Tcl)