Icon
- Дата создания:
- 1970
- Создан под влиянием:
- Повлиял на:
- Парадигма:
- Типизация:
- Принятые расширения файлов:
- .icn
- Диалекты:
- Реализации и версии (свернуть все | развернуть все):
Icon — высокоуровневый язык общего назначения, предназначенный для заданий, связанных с обработкой строк и структур данных.
Icon был создан в 1977 году в университете Аризоны. Цели и возможности языка похожи на SNOBOL, но Icon мало напоминает этот язык. Название этого языка было выбрано задолго до появления графических интерфейсов, поэтому с иконками оно не связано. Возможно, оно возникло в связи с “борьбой с предрассудками (iconoclasm)”, так как на момент создания Icon достаточно отклонялся от общих тенденций развития языков.
Icon — идеальный язык программирования для:
- Быстрого программирования. Если необходимо срочно написать программу, то Icon — лучший выбор, чем язык более низкого уровня.
- Тестирования идей. Если есть какая–либо идея, то её разумнее реализовать для испытания на работоспособность на Icon, чем на языке более низкого уровня.
- Написания небольших утилит. Зачастую нужно реализовать простенькую нетребовательную задачу — это будет намного легче и быстрее сделать на Icon.
- Обработки текста. Строки и таблицы в Icon реализованы таким образом, что обработка текстовой информации значительно упрощается.
- Программирования графики. Благодаря расширенной графической библиотеке в 9 версии Icon создавать графический интерфейс и работать с графикой становится намного проще.
Ключевая особенность языка Icon — это генераторы. Все императивные конструкции языка и все выражения являются выражениями. При передаче управления генератору он может возвращать неограниченное количество результатов. Например, выражение (1 to 5) — это генератор, возвращающий числа от 1 до 5.
procedure main ()
write (1 to 5)
end
Эта программа напишет только одно число, 1, потому что генератор 1 to 5 получит управление только один раз. Чтобы вывести на консоль числа от 1 до 5, программу можно составить так:
procedure main ()
local i
every i := 1 to 5 do
write (i)
end
или, что то же самое:
procedure main ()
every write (1 to 5)
end
every позволяет обработать все значения, которые возвращает выражение-аргумент.
В Icon есть большой класс выражений, возвращающих либо ни одного (fail), либо одно значение (succeed), то есть, это аналог логических выражений, являющийся частным случаем генераторов. Все логические и математические операции в Icon расширены, чтобы работать с генераторами.
Еще один удобный инструмент — сканирование строк: механизм привязки строки к выражению и ее сканирования специальными функциями, использующимися в этом выражении.
Сочетание обычных генераторов с логическими реализует принцип Generate and Test. Как и в Prolog, в Icon легко реализуется перебор, при этом в Icon можно постоянно варьировать стиль написания между императивным и логическим, в то время как в Prolog императивный код приходится насильно приводить к логическому представлению. Перебор особенно полезен при синтаксическом разборе текста. Несмотря на то, что для Icon есть аналоги lex и yacc, язык Icon настолько высокоуровневый, что разбор текста можно делать и без этих инструментов. В то время, как Perl является обёрткой для регулярных выражений, Icon является их эволюцией.
Спросите, зачем тогда нужны lex и yacc для Icon? Они позволяют сообщать пользователю, в каком месте что ожидалось и что было найдено взамен. Что ещё раз доказывает применимость Icon для тестирования идей. Если нужно проверить идею, Icon позволяет обойтись без профессиональных инструментов, которые, быть может, ещё не придуманы или их вообще не напишут в виду кратковременной необходимости.
Программисты нередко используют Icon для автоматизации генерации исходного кода, в том числе генерации тестов и текстовых преобразований, такие, как генерация промежуточного кода из IDL (COM, XPCOM, SOM, UNO, Protocol Buffers или т. п.). Использование Icon для обработки исходников на других языках замечено даже в Icon Programming Handbook.
Из интересных особенностей реализации: в Icon есть функции xencode()
и xdecode()
, сериализующие и десериализующие сложные структуры данных, при этом в этих структурах могут быть взаимопересечения и циклические ссылки. Топология после десериализации сохраняется. Более того, есть функция save()
, сохраняющая текущее состояние программы (все переменные, все адресуемые данные, стек, точки отката) в виде исполняемого файла.
Из минусов реализации: в Icon полностью отсутствует отладчик.
Элементы синтаксиса:
Комментарий до конца строки | # |
---|---|
Присваивание значения переменной | := или <- (обратимое при откате) |
Объявление переменной | local variable, или global variable, или static variable |
Блок | { ... } |
Равенство | = (для чисел) или == (для строк) |
Неравенство | ~= или ~== |
Тождественное равенство | === |
Тождественное неравенство | ~=== |
Сравнение | < > <= >= << >> <<= >>= |
Определение функции | procedure f(p1, p2, ...) ... end |
Вызов функции | f(a, b, ...) |
Вызов функции без параметров | f() |
Последовательность | ; |
Если - то | if condition then ... |
Если - то - иначе | if condition then ... else ... |
Бесконечный цикл | loop ... |
Цикл с предусловием | while condition do ... |
Цикл for - next для диапазона целых чисел с инкрементом на 1 | every i := 1 to 10 do ... |
Цикл for - next для диапазона целых чисел с декрементом на 1 | every i := 10 to 1 by -1 do ... |
Логотип Icon
Ссылки:
IDE/Редакторы:
Примеры:
Hello, World!:
Пример для версий iconc 9.4procedure main ()
write ("Hello, world!")
end
Факториал:
Пример для версий iconc 9.4Сокращенный вариант итеративного способа вычисления факториала.
procedure main ()
local i, j
every write (i := 0 to 16, "! = ", { j := 1; every j *:= 1 to i; j })
end
Факториал:
Пример для версий iconc 9.4В примере используется рекурсивное определение факториала. 0 to 16
— генератор, возвращающий все числа в интервале от 0 до 16. every
позволяет получить от генератора все числа и для каждого из них выполнить действие write
.
procedure factorial (n)
if n = 0 then
return 1
else if n > 0 then
return n * factorial (n - 1)
end
procedure main ()
local i
every i := 0 to 16 do
write (i, "! = ", factorial (i))
end
Числа Фибоначчи:
Пример для версий iconc 9.4Используется рекурсивное вычисление чисел Фибоначчи с мемоизацией промежуточных результатов
global fib_memo
procedure fib (n)
if n >= 0 then
return ((/fib_memo [n] := fib (n - 2) + fib (n - 1)) | fib_memo [n])
end
procedure main ()
local i
fib_memo := table ()
fib_memo [0] := 0; fib_memo [1] := 1
every i := 1 to 16 do {
writes (fib (i) || ", ")
}
write("...")
end
Квадратное уравнение:
Пример для версий iconc 9.4procedure main ()
A := read();
if A = 0 then {
write("Not a quadratic equation.");
return;
}
B := read();
C := read();
D := B*B - 4*A*C;
if D = 0 then {
write("x = ", -B/2/A);
return;
}
if D > 0 then {
write("x1 = ", (-B+sqrt(D))/2/A);
write("x2 = ", (-B-sqrt(D))/2/A);
} else {
write("x1 = (", -B/2/A, ",", sqrt(-D)/2/A, ")");
write("x2 = (", -B/2/A, ",", -sqrt(-D)/2/A, ")");
}
end
CamelCase:
Пример для версий iconc 9.4Прежде всего программа читает строку для обработки в переменную text
и добавляет в конец пробел (||
— оператор конкатенации). Затем переменная text
сканируется (?
— оператор сканирования, позволяющий привязать все операции поиска в строке к определенной переменной) следующим образом.
Команды ReFind
и ReMatch
из библиотеки регулярных выражений regexp
находят все последовательности символов, соответствующие регулярному выражению, но ReFind
возвращает индекс начала последовательности, а ReMatch
— первого символа после последовательности. За одну итерацию цикла ReFind
находит начало следующей последовательности не-букв. Команда tab
перемещает указатель на текущую позицию в сканируемой строке на это начало и возвращает подстроку от предыдущей позиции до новой — слово. Затем слово преобразуется к нужному формату и добавляется к результату. *word
— функция, возвращающая длину строки word
. map
заменяет символы первого аргумента, которые есть во втором, на их соответствия из третьего (в данном случае — заменяет друг на друга символы из &lcase
и &ucase
, встроенных переменных, содержащих алфавит в нижнем и верхнем регистре, соответственно). Наконец, еще одно обращение к tab
перемещает указатель на начало следующего слова (конец последовательности не-букв).
link regexp
procedure main ()
text := read() || " ";
cc := "";
text ? {
while j := ReFind("[^a-zA-Z]+") do {
word := tab(j);
cc ||:= map(word[1],&lcase,&ucase) || map(word[2:*word+1],&ucase,&lcase);
tab(ReMatch("[^a-zA-Z]+"));
}
}
write (cc);
end
Комментарии
]]>blog comments powered by Disqus
]]>