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

APL

Русское название:
АПЛ
Дата создания:
1961
Повлиял на:
Парадигма:
Типизация:
Реализации и версии (свернуть все | развернуть все):
Язык программирования

APL (от названия книги A Programming Language) — интерактивный матричный язык программирования, основанный на математической нотации Айверсона.

В 1956 году Кеннет Э. Айверсон, сотрудник Гарвардского университета (впоследствии сотрудник фирмы IBM и профессор названного университета) заявил о разрабатываемом им языке, который был закончен в 1961 г. Впервые этот язык был описан в 1962 году в книге Айверсона «A Programming Language» («Некий язык программирования»). Позднее язык был стандартизирован: ISO 8485:1989 описывает Core APL, ISO/IEC 13751:2001 — Extended APL. Кроме того, предпринимались попытки дополнить его современными возможностями — объектно-ориентированным программированием, работой с базами данных SQL и т.д.

Целью создания APL была разработка компактной системы записи (нотации) для описания алгоритмов прикладной математики. В изобретенной Айверсоном оригинальной нотации присутствует множество специфических соглашений и символов (кроме обычных знаков, в алфавите содержится 58 специфических, например, «сапог», «шапка», «посох», «дно» и т.д., и лигатуры — знаки, которые возникают при наложении друг на друга двух простых символов). Все это предназначено для точной и сжатой формулировки алгоритмов, которые затем можно интерпретировать на различные языки программирования. Таким образом, APL создавался не только как язык программирования, но в первую очередь как язык передачи идей. Первые реализации APL как языка программирования были созданы гораздо позже, чем его первые описания и использования для описаний других систем.

Основные особенности APL:

  • краткость: для записи функций и операторов используются одиночные символы. Кроме того, большинство символов используются в двух смыслах — как унарная и как бинарная функции, при этом эти функции могут быть достаточно непохожи.
  • необычный набор символов, разработанный специально для этого языка. В свое время для пишущих машинок создавались специальные расширения, предназначенные для написания программ на APL.
  • ориентированность на работу с массивами.
  • максимальная нагруженность смыслом всех функций и операторов: все они доступны в множестве вариантов функциональности в зависимости от количества и размерности аргументов (один аргумент или два, скаляры они или массивы и т.д.).
  • ориентированность на решение проблемы и описание алгоритма, независимость от архитектуры компьютера и операционной системы.
  • интерактивность: интерпретируемый APL стал одной из первых интерактивных сред вычислений, что внесло значительный вклад в его успех.
  • высокий уровень абстрактности.
  • сложность написания и еще большая сложность чтения кода.

APL предоставляет программисту богатый набор функций — средств обработки данных и их преобразования в другие данные. Использование функций в выражениях подчиняется простому правилу приоритета: правым аргументом бинарной функции (или единственным аргументом унарной) всегда является выражение справа от нее целиком. Приоритет можно контролировать в явном виде при помощи скобок, но чаще всего это не нужно. Это правило упрощает анализ иерархической структуры выражений: функции верхнего уровня всегда находятся слева в строке.

Важным элементом языка являются операторы, примерно соответствующие функциям высшего порядка в других функциональных языках. Операторы получают на вход данные или функции и создают функции. В большинстве реализаций APL набор операторов ограничен и фиксирован — инструментарий определения новых операторов отсутствует. Это отличает язык от других функциональных языков, включая его наследник J, в которых функции высшего порядка можно создавать без ограничений. Синтаксис использования операторов отличается от синтаксиса функций: операторы выполняются слева направо, а унарные операторы используют выражение слева в качестве аргумента.

Одна команда программы на APL выглядит как последовательность функций и операторов, применяющихся к массивам. В языке есть примитивные типы данных (скаляры) — числа и символы (логические значения моделируются числами 0 для false и 1 для true — прием, впервые примененный в APL). Все структуры данных в языке — массивы: одномерные векторы, двухмерные матрицы и многомерные мультитаблицы. Все функции изначально ориентированы на работу с массивами, хотя и могут применяться к скалярам (с разным эффектом в зависимости от размерности аргументов). Развитая система операций над массивами позволяет во многих случаях избежать использования явных команд управления потоком выполнения программы. Во многих реализациях императивных управляющих структур нет вообще, хотя последние реализации склоняются к их добавлению и использованию для того, чтобы подчеркнуть разделение структур данных и управляющих конструкций.

Для реализации разнородных структур данных используется принцип boxing: любой массив может “заключаться в коробку” и рассматриваться как скаляр. В таком представлении над ним нельзя производить операции, зато его можно включать (вкладывать) в другие массивы. Содержимое такого массива становится доступным после его “извлечения из коробки”. Эта же техника используется для передачи в функции трех и более аргументов (все функции APL могут принимать от 0 до 2 аргументов, включительно).

В настоящее время APL используется в финансовых и математических приложениях, и существует ряд реализаций, но его популярность пошла на убыль с середины 1980-ых годов, когда начали развиваться другие системы математических вычислений. Многие из них создавались под влиянием APL, но оказались более интуитивными и лучше предназначенными для конечного пользователя.

Элементы синтаксиса:

Комментарий до конца строки

Клавиатура APL
Клавиатура APL

Примеры:

Hello, World!:

Пример для версий Dyalog APL 13.1
'Hello, World!'

Факториал:

Пример для версий Dyalog APL 13.1

Первая строка задает значение индекса первого элемента в списках (в данном случае 0). Вторая строка задает точность при выводе чисел (она должна превышать длину максимального факториала).

Третья строка при чтении справа налево делает следующее:

  • ⍳17 генерирует список из 17 индексов, начинающихся с 0, т.е. 0 … 16.

  • 17 / ⊂'!=' генерирует список из 17 строк !=. — оператор enclose, который позволяет оперировать строками как скалярами, а не как массивами символов. / — оператор репликации.

  • !⍳17 применяет к каждому элементу списка унарную операцию ! — факториал.

  • , — бинарная операция конкатенации правого и левого аргументов; после двух конкатенаций выражение принимает значение 0 1 2 3 4 ... 15 16 != != ... != 1 1 2 6 24 120 720 5040 40320 362880 ..., т.е. список чисел, список строк и затем список факториалов.

  • 3 17⍴ изменяет форму списка-аргумента, получая из него матрицу из 3 строк и 17 столбцов:

    ┌→─┬──┬──┬──┬──┬───┬───┬────┬─────┬──────┬───────┬────────┬─────────┬──────────┬───────────┬─────────────┬──────────────┐  
    ↓0 │1 │2 │3 │4 │5  │6  │7   │8    │9     │10     │11      │12       │13        │14         │15           │16            │  
    ├~─┼~─┼~─┼~─┼~─┼~──┼~──┼~───┼~────┼~─────┼~──────┼~───────┼~────────┼~─────────┼~──────────┼~────────────┼~─────────────┤  
    │!=│!=│!=│!=│!=│!= │!= │!=  │!=   │!=    │!=     │!=      │!=       │!=        │!=         │!=           │!=            │  
    ├─→┼─→┼─→┼─→┼─→┼──→┼──→┼───→┼────→┼─────→┼──────→┼───────→┼────────→┼─────────→┼──────────→┼────────────→┼─────────────→┤  
    │1 │1 │2 │6 │24│120│720│5040│40320│362880│3628800│39916800│479001600│6227020800│87178291200│1307674368000│20922789888000│  
    └~─┴~─┴~─┴~─┴~─┴~──┴~──┴~───┴~────┴~─────┴~──────┴~───────┴~────────┴~─────────┴~──────────┴~────────────┴~─────────────┘
    
  • наконец, транспонирует эту матрицу так, что в каждой строке находятся три элемента — число, строка-разделитель и факториал числа.

В итоге вывод программы имеет следующий вид:

     ┌→─┬──┬──────────────┐          
     ↓0 │!=│1             │          
     ├~─┼─→┼~─────────────┤          
     │1 │!=│1             │          
     ├~─┼─→┼~─────────────┤          
     │2 │!=│2             │          
     ├~─┼─→┼~─────────────┤          
     [...25 lines of output ...]  
     ├~─┼─→┼~─────────────┤          
     │16│!=│20922789888000│          
     └~─┴─→┴~─────────────┘

Матрица оформлена как таблица с границами между ячейками из-за того, что она содержит boxed строки.

IO←0
⎕PP←18
⍉3 17⍴ (⍳17) , (17 /'!=') , !⍳17

Числа Фибоначчи:

Пример для версий Dyalog APL 13.1

В этом примере используется формула Бине, реализованная через анонимную динамическую функцию. — разделитель выражений, т.е. функция состоит из двух выражений, вычисляющихся слева направо. Первое из них вычисляет золотое сечение и ассоциирует его с именем phi. Второе — вычисляет значение функции через правый аргумент . — округление вверх.

Поскольку функция унарна и определяется через скалярные функции, ее можно применить к массиву, в данном случае к массиву номеров чисел Фибоначчи от 1 до 16, включительно. Результатом будет массив чисел Фибоначчи:

1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987

{phi(1+5*0.5)÷2 ⋄ ⌈((phi*) - (1-phi)*)÷5*0.5} 1+⍳16

Факториал:

Пример для версий Dyalog APL 13.1

В этом примере факториал числа N вычисляется как свертка списка чисел от 1 до N, включительно, при помощи выражения ×/1+⍳. Анонимная D-функция применяет это выражение к своему правому аргументу и конкатенирует его с самим аргументом и строкой-разделителем. Функция, в свою очередь, применяется к списку чисел от 0 до 16, записанному в столбик (т.е. как двухмерный массив 17x1). Вывод программы выглядит следующим образом:

 ┌→───────────────────┐      
 ↓0 != 1              │      
 ├+──────────────────→┤      
 │1 != 1              │      
 ├+──────────────────→┤      
 │2 != 2              │      
 ├+──────────────────→┤      
 [...25 lines of output ...]  
 ├+──────────────────→┤      
 │16 != 20922789888000│      
 └+──────────────────→┘
IO←0
⎕PP←18
{, '!=', ×/1+⍳⍵}¨17 1⍴⍳17

Числа Фибоначчи:

Пример для версий Dyalog APL 13.1

В данном примере используется анонимно D-функция, рекурсивно вызывающая сама себя. Первое выражение функции обрабатывает случай первых двух чисел Фибоначчи, равных единице. Для остальных чисел работает второе выражение, которое вызывает эту же D-функцию (функция ) для меньших значений аргументов и суммирует их. Первая строка ассоциирует массив чисел с переменной fib и ничего не выводит.

Во второй строке вычисленный массив чисел Фибоначчи выводится в нужном формате: к каждому элементу применяется функция, конкатенирующая его с запятой-разделителем, элементы получившегося массива конкатенируются друг с другом (,/) и к результату добавляется троеточие. Итоговый вывод этой команды выглядит следующим образом:

1 ,  1 ,  2 ,  3 ,  5 ,  8 ,  13 ,  21 ,  34 ,  55 ,  89 ,  144 ,  233 ,  377 ,  610 ,  987 , ...
fib{⍵≤2:1 ⋄ (∇⍵-1)+∇⍵-2}¨1+⍳16
((,/{, ', '}¨fib)),'...'

Квадратное уравнение:

Пример для версий Dyalog APL 13.1

В этом примере определяется именованная D-функция, которая принимает коэффициенты уравнения как один параметр — массив из трех элементов и выводит решение уравнения. Вначале параметр разбирается на отдельные коэффициенты, и им присваиваются имена (N⊃⍵ выбирает N-ый элемент массива). Затем выполняются проверки первого коэффициента и дискриминанта, по которым функция может вернуть нетипичное решение. Наконец, оба случая ненулевого дискриминанта обрабатываются одним и тем же кодом благодаря тому, что в APL есть встроенные комплексные числа. Например, вызов функции

solve 1 0 2

возвращает следующие значения:

0J1.4142135623730951 0J¯1.4142135623730951

(J — разделитель действительной и мнимой частей числа, ¯ — “высокий” минус, использующийся для ввода/вывода отрицательных чисел).

Отметим, что данный код является нетипичным для APL из-за использования условного ветвления, а также из-за того, что механизм использования аргумента ограничивает диапазон его возможных значений до одномерного массива из трех элементов.

solve←{A0⊃⍵  B1⊃⍵  C2⊃⍵  A=0:'Not a quadratic equation.'  D(B*2)-4×A×C  D=0:-0.5×B÷A  ((-B-D*0.5), -B+D*0.5)×0.5÷A}

Комментарии

]]>

blog comments powered by Disqus

]]>

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