]]> ]]>
Править | Обсудить | История

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
Логотип Icon

IDE/Редакторы:

Примеры:

Hello, World!:

Пример для версий iconc 9.4
procedure 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.4
procedure 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

]]>

Работа программистам