Существует интерактивная (и немного улучшенная) версия этой статьи на сайте wordsandbuttons.online: http://wordsandbuttons.online/apl_deserve_its_renaissance_too.html

Это Игра жизни в APL: life←{↑1 ⍵∨.∧3 4=+/,¯1 0 1∘.⊖¯1 0 1∘.⌽⊂⍵}

Я знаю я знаю. Я должен был начать с введения, но разве оно не достаточно хорошо представляется? Вы сами можете убедиться, что он в конечном итоге лаконичен, выразителен и полностью чужд всем распространенным компьютерным языкам.

На самом деле он вообще не возник как компьютерный язык. Это было предложено в качестве лучшей записи для тензорной алгебры математиком из Гарварда Кеннетом Э. Айверсоном. Он должен был быть написан от руки на доске для передачи математических идей от одного человека к другому.

Но из-за своей формальности передача идей от людей к компьютерам оказалась на удивление хорошей. Он был превращен в компьютерный язык в начале 60-х, и эти странные символы, такие как или , вообще не были проблемой, потому что у каждого производителя в то время и так был свой собственный набор символов. ASCII еще даже не ратифицировали.

Его популярность росла в последующие годы, достигнув пика в 70-х годах, а затем пошла на убыль с появлением персональных компьютеров на базе BASIC и платформы UNIX на основе C. Он все еще используется в некоторых нишах, например, в финансовом секторе, а это означает, что люди фактически зарабатывают деньги с помощью APL и по сей день. Но что удивительно, самый первый портативный компьютер от IBM - IBM 5100 «пакет интерактивных персональных вычислений весом 50 фунтов» - появился на 6 лет раньше IBM PC и с APL на борту.

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

И вообще выучить язык не так уж и сложно. Вы можете не поверить в это, но это один из самых простых языков на свете. Здесь позвольте мне показать вам, как работает Игра Жизни.

Левая стрелка - это функция присваивания, а скобки отмечают тело функции. Итак, это: life←{...}это просто определение функции.

Аргументы функции APL являются неявными, то есть вам не нужно указывать имя для каждого аргумента, вы просто знаете по соглашению, что левый аргумент всегда ⍺, а правый. Разве это не означает, что функции APL принимают не более двух аргументов? Не совсем. Если вы хотите вызвать C-подобную функцию, например: foo(x, y, z), в терминах APL вы просто передаете кортеж из 3 значений. Но он все еще один ⍵.

Давайте проведем нашу жизнь с некоторым вкладом. Пусть будет планировщик. Мы будем использовать функцию, чтобы сформировать матрицу из линейного массива.

in ← 5 5 ⍴ 0 0 0 0 0  0 0 1 0 0  0 0 0 1 0  0 1 1 1 0  0 0 0 0 0
in
0 0 0 0 0
0 0 1 0 0
0 0 0 1 0
0 1 1 1 0
0 0 0 0 0

Запуск life for in приведет к следующему:

life in
0 0 0 0 0
0 0 0 0 0
0 1 0 1 0
0 0 1 1 0
0 0 1 0 0

Планировщик переехал!

В APL то, что мы называем операторами, тоже являются функциями. Такие вещи, как +, -, * и т. Д. Функции выполняются одновременно справа налево. Нет приоритета, все функции равны.

Первой функцией тела life будет enclose: . Что он делает - он превращает входные данные матрицы 5x5 в скаляр, содержащий матрицу 5x5.

⊂ in
┌─────────┐
│0 0 0 0 0│
│0 0 1 0 0│
│0 0 0 1 0│
│0 1 1 1 0│
│0 0 0 0 0│
└─────────┘

Следующий - немного сложнее. Следующая функция - повернуть: . Он вращает массив по заданному индексу.

1 ⌽ 1 2 3
2 3 1
0 ⌽ 1 2 3
1 2 3
¯1 ⌽ 1 2 3
3 1 2

Но это не происходит само по себе. Он сам по себе является аргументом для оператора внешнего произведения: ∘. (в функциях APL, которые принимают функции в качестве аргументов, они называются операторами).

И вместе они делают это:

¯1 0 1∘.⌽⊂in
┌─────────┬─────────┬─────────┐
│0 0 0 0 0│0 0 0 0 0│0 0 0 0 0│
│0 0 0 1 0│0 0 1 0 0│0 1 0 0 0│
│0 0 0 0 1│0 0 0 1 0│0 0 1 0 0│
│0 0 1 1 1│0 1 1 1 0│1 1 1 0 0│
│0 0 0 0 0│0 0 0 0 0│0 0 0 0 0│
└─────────┴─────────┴─────────┘

Следующая функция также связана с оператором. Это сначала повернуть: . Он работает почти так же, как rotate, но вращает вложенный массив вокруг первого уровня «вложенности».

1 ⊖ in
0 0 1 0 0
0 0 0 1 0
0 1 1 1 0
0 0 0 0 0
0 0 0 0 0
0 ⊖ in
0 0 0 0 0
0 0 1 0 0
0 0 0 1 0
0 1 1 1 0
0 0 0 0 0
¯1 ⊖ in
0 0 0 0 0
0 0 0 0 0
0 0 1 0 0
0 0 0 1 0
0 1 1 1 0

С оператором внешнего продукта и нашим предыдущим результатом это выглядит так:

¯1 0 1∘.⊖¯1 0 1∘.⌽⊂in
┌─────────┬─────────┬─────────┐
│0 0 0 0 0│0 0 0 0 0│0 0 0 0 0│
│0 0 0 0 0│0 0 0 0 0│0 0 0 0 0│
│0 0 0 1 0│0 0 1 0 0│0 1 0 0 0│
│0 0 0 0 1│0 0 0 1 0│0 0 1 0 0│
│0 0 1 1 1│0 1 1 1 0│1 1 1 0 0│
├─────────┼─────────┼─────────┤
│0 0 0 0 0│0 0 0 0 0│0 0 0 0 0│
│0 0 0 1 0│0 0 1 0 0│0 1 0 0 0│
│0 0 0 0 1│0 0 0 1 0│0 0 1 0 0│
│0 0 1 1 1│0 1 1 1 0│1 1 1 0 0│
│0 0 0 0 0│0 0 0 0 0│0 0 0 0 0│
├─────────┼─────────┼─────────┤
│0 0 0 1 0│0 0 1 0 0│0 1 0 0 0│
│0 0 0 0 1│0 0 0 1 0│0 0 1 0 0│
│0 0 1 1 1│0 1 1 1 0│1 1 1 0 0│
│0 0 0 0 0│0 0 0 0 0│0 0 0 0 0│
│0 0 0 0 0│0 0 0 0 0│0 0 0 0 0│
└─────────┴─────────┴─────────┘

Следующая функция называется ravel: ,, и она действительно похожа на кому. Что он делает, он превращает вложенный массив в одномерный.

, in
0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 1 1 1 0 0 0 0 0 0

Он не использует скаляр, поэтому, применяя его к нашей матрице скаляров, содержащей матрицы, он будет представлять собой массив из 9 закрытых матриц.

Следующая - снова пара оператора и функции. Оператор уменьшить: / и функция плюс: +. Как вы могли догадаться, это уменьшает суммирование всех матриц в массиве:

+/,¯1 0 1∘.⊖¯1 0 1∘.⌽⊂in
┌─────────┐
│0 1 1 1 0│
│0 1 2 2 1│
│1 3 5 4 2│
│1 2 4 3 2│
│1 2 3 2 1│
└─────────┘

Сравнение операторов: = производит матрицы из 0 и 1 в зависимости от того, равен ли каждый элемент в правом аргументе каждому аргументу в левом аргументе. В нашем случае это приведет к:

3 4 = +/,¯1 0 1∘.⊖¯1 0 1∘.⌽⊂in
┌─────────┬─────────┐
│0 0 0 0 0│0 0 0 0 0│
│0 0 0 0 0│0 0 0 0 0│
│0 1 0 0 0│0 0 0 1 0│
│0 0 0 1 0│0 0 1 0 0│
│0 0 1 0 0│0 0 0 0 0│
└─────────┴─────────┘

Тогда есть логическая часть. Функции или: и и: используются с оператором внутренний продукт .. С нашим вводом это приводит к закрытой матрице, где каждый 1 элемент исходного ввода приводит к тому, что 1 имеет только 2 исходных соседа, но также каждый элемент вообще приводит к тому, что 1 имеет 3 соседа, независимо от того, был ли он установлен на 1 в исходном вводе или нет.

Это в основном правила Игры в жизнь.

1 in∨.∧3 4=+/,¯1 0 1∘.⊖¯1 0 1∘.⌽⊂in
┌─────────┐
│0 0 0 0 0│
│0 0 0 0 0│
│0 1 0 1 0│
│0 0 1 1 0│
│0 0 1 0 0│
└─────────┘

И последняя функция mix здесь просто удаляет вложенность.

↑1 in∨.∧3 4=+/,¯1 0 1∘.⊖¯1 0 1∘.⌽⊂in
0 0 0 0 0
0 0 0 0 0
0 1 0 1 0
0 0 1 1 0
0 0 1 0 0

Совсем не чуждо сейчас, не так ли?

Но почему он все-таки заслуживает возрождения?

Он был разработан для написания от руки. Однако в течение десятилетий он вводился только с клавиатуры. И странная, не та, которую можно просто купить в любом магазине. Однако у APL есть свои ASCII-дружественные потомки, унаследовавшие его выразительность и лаконичность, но, честно говоря, все они уродливы, за пределами возможности общественного успеха. Дело не в том, что APL чужды компьютерам, просто компьютеры были чужды APL на долгое время.

Но теперь, с развитием сенсорных интерфейсов и оптического распознавания символов, у него может появиться второй шанс. Лично я предпочел бы рисовать несколько строк символов APL на планшете, чем набирать сотни строк на Python с виртуальной клавиатурой.

Хакерский полдень - это то, с чего хакеры начинают свои дни. Мы часть семьи @AMI. Сейчас мы принимаем заявки и рады обсуждать рекламные и спонсорские возможности.

Если вам понравился этот рассказ, мы рекомендуем прочитать наши Последние технические истории и Современные технические истории. До следующего раза не воспринимайте реалии мира как должное!