Объясните мне конкатенативные языки, как будто мне 8 лет
Я прочитал статью в Википедии о конкатенативных языках, и теперь я в замешательстве, чем когда я начинал.:-)
Что такое конкатенативный язык в терминах глупых людей?
7 ответов
На ваш простой вопрос вот субъективный и аргументированный ответ.
Я посмотрел на статью и несколько связанных веб-страниц. Веб-страницы сами говорят, что настоящей теории нет, поэтому неудивительно, что людям трудно придумать точное и понятное определение. Я бы сказал, что в настоящее время бесполезно классифицировать языки как "конкатенационные" или "не конкатенационные".
Для меня это выглядит как термин, который дает Манфреду фон Туну место, где можно повесить шляпу, но может оказаться бесполезным для других программистов.
В то время как PostScript и Forth стоит изучить, я не вижу ничего ужасно нового или интересного в языке программирования Manfred von Thun's Joy. В самом деле, если вы читаете статью Криса Окасаки о методах встраивания языков постфикса в Haskell, вы можете попробовать все эти вещи в обстановке, которая, по сравнению с Joy, является абсолютно мейнстримом.
Так что мой ответ - нет простого объяснения, потому что нет зрелой теории, лежащей в основе идеи конкатенативного языка. (Как сказали Эйнштейн и Фейнман, если вы не можете объяснить свою идею первокурснику из колледжа, вы на самом деле не понимаете ее.) Я пойду дальше и скажу, что изучение некоторых из этих языков, таких как Forth и PostScript, является превосходное использование времени, попытка выяснить, что именно люди имеют в виду, когда говорят "конкатенация", вероятно, является пустой тратой вашего времени.
В обычных языках программирования у вас есть переменные, которые можно свободно определять, и вы вызываете методы, используя эти переменные в качестве аргументов. Они просты для понимания, но несколько ограничены. Часто трудно повторно использовать существующий метод, потому что вы просто не можете отобразить существующие переменные в параметры, которые нужны методу, или метод A вызывает другой метод B, и A подойдет вам, если вы сможете заменить вызов только B с призывом к C.
Конкатенационный язык использует фиксированную структуру данных для сохранения значений (обычно это стек или список). Там нет переменных. Это означает, что многие методы и функции имеют один и тот же "API": они работают с чем-то, что кто-то еще оставил в стеке. Плюс сам код считается "данными", то есть обычно пишется код, который может изменять себя или который принимает другой код в качестве "параметра" (т.е. как элемент в стеке).
Эти атрибуты делают эти языки идеальными для создания цепочки существующего кода для создания чего-то нового. Встроенное повторное использование. Вы можете написать функцию, которая принимает список и фрагмент кода и вызывает код для каждого элемента в списке. Теперь это будет работать с любыми типами данных, если они ведут себя как список: результаты из базы данных, ряд пикселей из изображения, символы в строке и т. Д.
Самая большая проблема в том, что у вас нет намека на то, что происходит. Существует только пара типов данных (список, строка, число), поэтому все сопоставляется с этим. Когда вы получаете часть данных, вам, как правило, все равно, что это и откуда. Но это затрудняет отслеживание данных через код, чтобы увидеть, что с ним происходит.
Я считаю, что для успешного использования языков требуется определенный настрой. Они не для всех.
[EDIT] Форт имеет некоторое проникновение, но не так много. Вы можете найти PostScript в любом современном лазерном принтере. Так что они нишевые языки.
С функционального уровня они находятся на одном уровне с LISP, C-подобными языками и SQL: все они Turing Complete, так что вы можете вычислить что угодно. Это просто вопрос того, сколько кода вы должны написать. Некоторые вещи более просты в LISP, некоторые более просты в C, некоторые более просты в языках запросов. Вопрос "лучше" бесполезен, если у вас нет контекста.
Сначала я собираюсь опровергнуть утверждение Нормана Рэмси о том, что теории нет.
Теория конкатенативных языков
Конкатенационный язык - это функциональный язык программирования, где операцией по умолчанию (что происходит, когда два термина находятся рядом) является составление функции вместо приложения функции. Это так просто.
Так, например, в исчислении SKI Combinator (одном из самых простых функциональных языков) два термина бок о бок эквивалентны применению первого термина ко второму. Например: S K K
эквивалентно S(K)(K)
,
На конкатенативном языке S K K
будет эквивалентно S . K . K
в Хаскеле.
Так в чем же дело
Чистый конкатенационный язык обладает тем интересным свойством, что порядок оценки терминов не имеет значения. На конкатенативном языке (S K) K
такой же как S (K K)
, Это не относится к исчислению SKI или любому другому функциональному языку программирования, основанному на функциональном приложении.
Одна из причин, по которой это наблюдение интересно, поскольку он открывает возможности для распараллеливания при оценке кода, выраженного в терминах композиции функций, а не приложения.
Теперь для реального мира
Семантика стековых языков, которые поддерживают функции высшего порядка, может быть объяснена с помощью конкатенационного исчисления. Вы просто отображаете каждый термин (команда / выражение / подпрограмма) как функцию, которая принимает функцию в качестве входных данных и возвращает функцию в качестве выходных данных. Вся программа фактически является функцией преобразования одного стека.
Реальность такова, что в реальном мире все всегда искажается (например, FORTH имеет глобальный словарь, PostScript делает странные вещи, где важен порядок оценки). Большинство практических языков программирования не совсем соответствуют теоретической модели.
Заключительные слова
Я не думаю, что обычный программист или 8-летний должен когда-либо беспокоиться о том, что такое язык конкатенации. Я также не нахожу это особенно полезным для языков программирования голубиного типа, как типа X или Y.
Прочитав http://concatenative.org/wiki/view/Concatenative%20language и опираясь на то, что я мало помню о том, как возился с Фортом в подростковом возрасте, я считаю, что ключевой момент в конкатенативном программировании связан с:
- просмотр данных в терминах значений в конкретном стеке данных
- и функции, управляющие вещами в терминах выталкивания / выталкивания значений в один и тот же стек данных
Проверьте эти цитаты из вышеупомянутой веб-страницы:
Существует два термина: язык стеков и язык конкатенизации. Оба определяют похожие, но не равные классы языков. Хотя по большей части они идентичны.
Большинство языков, широко распространенных сегодня, являются аппликативными языками: центральной конструкцией в языке является некая форма вызова функции, где функция применяется к набору параметров, где каждый параметр сам является результатом вызова функции, имени переменная или константа. В языках стека вызов функции выполняется простым написанием имени функции; параметры неявные, и они уже должны быть в стеке, когда выполняется вызов. Результат вызова функции (если таковой имеется) затем остается в стеке после возврата функции для использования следующей функцией и так далее. Поскольку функции вызываются простым упоминанием их имени без какого-либо дополнительного синтаксиса, Forth и Factor называют функции "словами", потому что в синтаксисе они на самом деле являются просто словами.
Это в отличие от прикладных языков, которые применяют свои функции непосредственно к конкретным переменным.
Пример: добавление двух чисел.
Аппликативный язык:
int foo(int a, int b)
{
return a + b;
}
var c = 4;
var d = 3;
var g = foo(c,d);
Язык конкатенации (я придумал, должен быть похож на Forth...;))
push 4
push 3
+
pop
Хотя я не думаю, что язык сцепления = язык стека, как указывают авторы выше, он кажется похожим.
Я считаю, что основная идея: 1. Мы можем создавать новые программы, просто объединяя другие программы.
Кроме того, 2. Любой случайный фрагмент программы является допустимой функцией (или подпрограммой).
У старого доброго чистого RPN Forth есть те свойства, исключая любой случайный синтаксис не RPN.
В программе 1 2 + 3 * подпрограмма + 3 * принимает 2 аргумента и дает 1 результат. Подпрограмма 2 принимает 0 аргументов и возвращает 1 результат. Любой кусок - это функция, и это хорошо!
Вы можете создавать новые функции, смешивая две или более других вместе, по желанию с небольшим количеством клея. Это будет работать лучше всего, если типы совпадают!
Эти идеи действительно хороши, мы ценим простоту.
Он не ограничивается ни последовательным языком в стиле RPN Forth, ни императивным или функциональным программированием. Эти две идеи также работают для графического языка, где программными единицами могут быть, например, функции, процедуры, отношения или процессы.
В сети взаимодействующих процессов каждая подсеть может действовать как процесс.
В графе математических отношений каждый подграф является действительным отношением.
Эти структуры являются "конкатенативными", мы можем разбить их любым способом (нарисовать круги) и соединить их разными способами (нарисовать линии).
Ну вот как я это вижу. Я уверен, что пропустил много других хороших идей из конкатенационного лагеря. В то время как я увлекаюсь графическим программированием, я новичок в этом сосредоточении на конкатенации.
Мое прагматическое (и субъективное) определение для конкатенативного программирования (теперь вы можете избежать прочтения всего остального):
-> Композиция функций экстремальными способами (с синтаксисом RPN):
( Forth code )
: fib
dup 2 <= if
drop 1
else
dup 1 - recurse
swap 2 - recurse +
then ;
-> все является функцией или, по крайней мере, может быть функцией:
( Forth code )
: 1 1 ; \ define a function 1 to push the literal number 1 on stack
-> аргументы передаются неявно через функции (хорошо, похоже, это определение для неявного программирования), но это в Forth:
a b c
может быть в Лиспе:
(c a b)
(c (b a))
(c (b (a)))
так что легко генерировать неоднозначный код... вы можете написать определения, которые помещают xt (токен выполнения) в стек и задают небольшой псевдоним для "execute":
( Forth code )
: <- execute ; \ apply function
Итак, вы получите:
a b c <- \ Lisp: (c a b)
a b <- c <- \ Lisp: (c (b a))
a <- b <- c <- \ Lisp: (c (b (a)))
Вы не можете объяснить язык, просто возьмите его (желательно фактор) и попробуйте несколько уроков по нему. Учебники лучше, чем ответы на переполнение стека.