Практика мультипарадигмального программирования, 02 лекция (от 19 февраля)
Материал из eSyr's wiki.
Предыдущая лекция | Следующая лекция
Основная тема — способы сочетания нескольких парадигм.
Содержание |
Tcl
Мультипарадигмальный язык (?)
Запуск
$tclsh
Это оболочка. Понимает внешние команды.
Вывод строки: puts «Hello»
Без перевода строки: nonewline
Установка переменной: set myvar val
Получение значения: $myvar
Ассоц массивы: set myarray(27) {val}
Внутри фиг скобок обратный слеш не действует, подстановки не действуют
Квадратные скобки — подставление результата (почти то же, что обратные кавычки в шелле, но не то, что печатают, а действительно результат)
Математика
есть expr. Склеивает все аргументы и воспринимает как арифм выражение
Допустим, есть переменная, которая получает значение извне (от пользователся, по сети). Что в такой ситуации может получиться:
% set userinput {[puts DANGER!]} [puts DANGER!] %expr {$userinput == 1} 0 %expr {$userinput == 1} %expr $userinput == 1 DANGER! 0
Почему так происходит: происходит подстановка и вычисляется значение внутри квадратных скобок. Правило: внутри expr лучше всегда использовать фигурные скобки.
Арифметические операции как в Си. Числа бывают с плавающей точкой и целые. Есть побитовые операции, логические связки. Кроме того, есть:
- eq — сравнение строк на эквивалентность
- ne — на неэквив
- in — в списке
- ni — не в списке
Есть математические функции
Управляющие конструкции
if
if <условие> then <oper> else
условие вычисляется так же, как expr, then необязателен, else тоже
В реальной жизни делают иначе:
if {$x == 1} { ... } { ... }
При этом многие не понимают, что фигурные скобки это не операторные скобки. В качестве условия может дать число (0 ложь, 1 истина), строки «yes»/»no», «true»/»false», остальные слова вызывают ошибку.
switch
switch <expr> { <expr> { ... } <expr> { ... } default { ... } }
На самом деле, switch можно записать совсем иначе:
switch $x "one" "puts 1" \ "two" "puts 2" "three" "puts 3" \ default "puts Unknown"
Если первое выражение не воспринимается, как список, то оно идёт дальше до дефолт (?)
while
while <усл> <body>
for
for <start> <condition> <next> <body>
Если это написать вот так:
for {set i 0} {$i < 10} {set i [expr $i+1]}
то будет совсем похоже на Си.
Процедуры
proc <name> <params> <body>
Пример:
proc sum {x y} { return [expr {$x+$y}] }
Объявление переменных
В процедурах все переменные, если не сказано обратного, считаются локальными.
Глобальная переменная:
global z — будет глобальная upvar — связывает с переменной, которая в том контексте, в котором определена процедурах
Комментарии
# ...
Комментарии не от начала строки, а от начала оператора. То есть, если хотим на той же строчке комментарий, то надо поставить точкой с запятой.
Списки
В последних версиях Tcl есть своё внутреннее представление (например, число хранится как число), поэтому он эффективнее шелла. Посему, так как списки хранятся как списки, то работа с ними эффективна.
Работа со списками
Задание списков
set lst {{item 1} {item 2} {item 3}}
set lst [split "Item1.Item2.Item3" "."]
set lst [list "Item1" "Item2" "Item3"]
Самое забавное здесь, что в первом случае внутренние скобки на кавычки заменять нельзя.
Индексирование
lindex <list> <index>
Выделяет элемент. Индексы с 0.
Длина
llength <list>
Объединение
concat
Добавление элементов
lappend <list> <...>
Вставка в середину
linsert <list> <index> <arg> ...
Замена
lreplace <list> <first> <last> <...> <...>
Установить такому элементу списка такое значение
lset <listName> <index> <newValue>
Работа со строками
Есть команда string, которая со строкаим делает всё. На самом деле, она состоит из двух слов, и второе обозначает команду.
string length <str> — длина string compare string bytelength — размер в байтах string trim — отбросить незначащие пробелы string topupper string tolower string range string index string match <pattern> <str>— берётся строка и сравнивается с образцом. В образце могут быть "*", "?"
[glob /usr/bin/*] — список всех файлов в /usr/bin/
Решулярные выражения
Единственный командный язык, в котором нет регулярных выражений, известный лектору, это bourne shell.
regexp пытается сопоставить строку целиком regsub пытается сопоставить произвольную подстроку
Массивы
Есть ассоциативные массивы. Для них есть всеобъемлющая комманда array
array exists — есть ли значение array names — все существующие индексы данного массива array size array get — из списка массив array set — из массива список
В списке идёт "индекс значение ..."
Работа с файлами
Чуть ли не лучше, чем в шелле
- open <filename> <access> <permissions (по умолчанию 0666)>
- access — r, w, r+, w+, a+, a
- Возвращает нечто, являющее файловым дескриптором
- close — единственный прааметр — результат open
read, write, tell, eof ...
read возвращает пустую строку в обоих случаях, eof позволяет различить ситуацию
fconfigure позволяет сконфигурировать для работы с бинарными файлами
Парадигмальный аспект
Здесь абсолютно всё является строкой. И for, while — обычная процедура, которую можно переопределить. В отличие от лиспа, создатели tcl умудрились обойтись без специальных форм.
Tcl не получил бы широкого распространения, если бы не его свойства: может встраиваться, может расширяться, самое интересно, если встраивать, предварительно расширить. Пример:
IRCII. Прямой потомок BitchX. Оба содержат интерпретатор Tcl. причём, очень интнресно: в далёков 94 году IRC был безумно популярен. Тогда был IRCII, и тогда была такая вещь, как скрипты, можно было разные действия, например, устраивать войны, как то захват канала. И лектор пытался разобраться в скриптах, и пытался узнать у коллег, где взять ман, но никто не раскололся. Позже, в 2002 году, когда лектор начал программировать на Tcl, он это понял.
В чистом виде Tcl не очень осмысленный, но если лень возиться с перенаправлениями и каналами, можно воспользоваться им. Tcl полезен, если язык, куда он встраивается, проблемно-ориентированный.
Имеется н-е количество сишных функций для работы с интерпретатором Tcl. Пример:
#include <stdio.h> #include <tcl.h>
int main() { Tcl_Interp * interp = Tcl_CreateInterp(); Tcl_Eval(interp, "proc p1 {arg1} {list $arg1 $arg1 $arg1}"); Tcl_Eval(interp, "p1 foobar"); printf("%s\n", Tcl_GetStringResult(interp)); Tcl_DeleteInterp(interp); return 0; }
Как компилировать:
gcc -Wall -g -ltcl embed.c -o embed
Практика мультипарадигмального программирования
Календарь
пн | пн | пн | пн | пн | |
Февраль
| 12 | 19 | |||
Март
| 12 | 19 | 26 | ||
Апрель
| 02 | 09 | 16 |