Статья: Почему конкатенативное программирование имеет значение
Why Concatenative Programming MattersСодержание по версии Google Translate
Код:
12 февраля 2012 г.
Почему конкатенативное программирование имеет значение
Введение
Кажется, что нет хорошего учебника для конкатенативного программирования, поэтому я решил написать его, вдохновленный классической статьей Джона Хьюза «Почему функциональное программирование имеет значение». Если повезет, это заинтересует больше людей этой темой и даст мне URL-адрес, который я смогу передать людям, когда они спросят, какого черта я так взволнован.
Прежде всего, похоже, существуют некоторые разногласия по поводу того, что на самом деле означает термин «конкатенативный». Этот ответ Нормана Рэмси о переполнении стека заходит так далеко, что говорит:
«… Бесполезно использовать слово« конкатенативный »для описания языков программирования. Это место похоже на частную игровую площадку Манфреда фон Туна . Нет реального определения того, что составляет конкатенативный язык, и нет зрелой теории, лежащей в основе идеи конкатенативного языка ».
Это довольно жестко и, что ж, неправильно. Не совсем неправильно, ум, скорее неправильно. Но неудивительно, что такая дезинформация распространяется, потому что конкатентивное программирование не так хорошо известно. (Я стремлюсь изменить это.)
Конкатенативное программирование называется так потому, что оно использует композицию функций вместо приложения функций - неконкатенативный язык, таким образом, называется аппликативным . Это определяющее различие, и это настолько «настоящее» определение, насколько мне нужно, потому что, ну, это то, что люди используют. Взрыв. Дескриптивизм.
Одна из проблем функционального программирования состоит в том, что часто рекламируемые преимущества - неизменность, ссылочная прозрачность, математическая чистота и т. Д. - не сразу начинают применяться в реальном мире. Причина, по которой «Функциональное программирование имеет значение» было необходимо в первую очередь, заключалась в том, что функциональное программирование было неправильно охарактеризовано как парадигма негативов - без мутации, без побочных эффектов - поэтому все знали, что вы не можете сделать, но мало кто понимал, что ты мог бы .
Аналогичная проблема существует и с конкатенативным программированием. Взгляните на введение в Википедии:
Конкатенативный язык программирования - это язык программирования без точек, в котором все выражения обозначают функции, а их сопоставление обозначает композицию функций. Комбинация композиционной семантики с синтаксисом, который отражает такую семантику, делает конкатенативные языки легко поддающимися алгебраическим манипуляциям.
Все это правда - и все это не имеет отношения к вашей непосредственной проблеме, почему вам следует заботиться . Итак, в следующих разделах я покажу вам:
Как работает конкатенативное программирование
Как работает набор на конкатенативном языке
Насколько эффективны конкатенативные языки
Какие конкатенативные языки не подходят
Куда обратиться за дополнительной информацией
А теперь приступим!
♦ ♦ ♦
Основы
В прикладном языке функции применяются к значениям для получения других значений. λ-исчисление, основа функциональных языков, формализует приложение как «β-редукцию», которая просто говорит о том, что если у вас есть функция ( f x = x + 1), то вы можете заменить вызов этой функции ( f y ) на его результат ( y + 1). В λ-исчислении простое сопоставление ( f x ) обозначает приложение, но композиция функции должна обрабатываться с помощью явной функции композиции:
составить: = λ f . λ г . λ х . f ( g x )
В этом определении говорится, что «композиция (составить) двух функций ( f и g ) является результатом применения одной ( f ) к результату другой ( g x )», что в значительной степени является буквальным определением. Обратите внимание, что эту функцию можно использовать только для составления функций с одним аргументом - подробнее об этом позже.
В конкатенативных языках композиция неявна : « f g » - это композиция f и g . Однако это не означает, что приложение функции становится явным - оно фактически становится ненужным . И, как оказалось, этот странный факт значительно упрощает создание, использование и рассуждение этих языков.
Нетипизированное λ-исчисление - относительно простая система. Однако для него и многих систем, производных от него, по-прежнему требуются три вида терминов - переменные, лямбда-выражения и приложения, а также ряд правил о том, как правильно заменять имена переменных при применении функций. Вы должны иметь дело с привязкой имен, замыканиями и областью видимости. Предположительно низкоуровневому языку присуща немалая сложность.
Конкатенативные языки имеют гораздо более простую основу - есть только функции и композиции , а вычисление - это просто упрощение функций. Нет необходимости иметь дело с именованным состоянием - здесь нет переменных. В некотором смысле конкатенативные языки «более функциональны», чем традиционные функциональные языки! И все же, как мы увидим, их также легко реализовать эффективно.
♦ ♦ ♦
Состав
Допустим, мы хотим умножить пару чисел. На типичном конкатенативном языке это выглядит так:
2 3 ×
В этом есть две странные вещи.
Во-первых, мы используем постфиксную нотацию (2 3 ×), а не префиксную нотацию (× 2 3), которая является общей в функциональном мире, или инфиксную нотацию (2 × 3), которую большинство языков предоставляют для удобства. Ничто не мешает конкатенативному языку иметь инфиксные операторы, но ради единообразия большинство придерживается постфиксной записи: « f g » означает ( g ∘ f ), то есть обратное по отношению к композиции функций. На самом деле это довольно приятное обозначение, потому что оно означает, что данные передаются в том порядке, в котором написаны функции.
Во-вторых, мы сказали, что все термины обозначают функции - так что, черт возьми, 2 и 3 там делают? Они действительно кажутся мне ценностями! Но если вы немного наклоните голову, вы также можете увидеть их как функции: значения не принимают аргументов и возвращаются сами . Если бы мы записали входы и выходы этих функций, это выглядело бы так:
2 :: () → (число)
3 :: () → (число)
Как вы можете догадаться, « x :: T » означает « x имеет тип T », а « T 1 → T 2 » означает «функцию от типа T 1 к типу T 2 ». Таким образом, эти функции не принимают ввода и возвращают одно целое число. Мы также знаем тип функции умножения, которая принимает два целых числа и возвращает только одно:
× :: (число, число) → (число)
Как теперь собрать все эти функции вместе? Помните, мы говорили, что « f g » означает (обратную) композицию f и g , но как мы можем составить 2 с 3, если их входы и выходы не совпадают? Вы не можете передать целое число функции, которая не принимает аргументов.
Решение заключается в том, что называется полиморфизмом стека . По сути, мы можем дать этим функциям общий полиморфный тип, в котором говорится, что они будут принимать любые входные данные, а затем то, что им действительно нужно. Они возвращают аргументы, которые не используют, за которыми следует фактическое возвращаемое значение:
2 :: ∀ . ( ) → ( , целое) 3 :: ∀ . ( ) → ( , целое) × :: ∀ . ( A , int, int) → ( A , int)
«∀ A ». означает «Для всех А » - в этих примерах, даже если в А есть запятые. Итак, теперь смысл выражения «2 3» ясен: это функция, которая не принимает входных данных и возвращает как 2, так и 3. Это работает, потому что, когда мы составляем две функции, мы сопоставляем выход одной с входом прочее, поэтому начнем со следующих определений:
2 :: ∀ . ( ) → ( , Int ) 3 :: ∀ Б . ( B ) → ( B , интервал)
Подбираем типы:
( A , число ) = ( B )
Подставляя, мы получаем новый полиморфный тип для 3 внутри выражения:
3 :: ∀ С . ( C , интервал ) → ( C , интервал , интервал)
Это соответствует неполиморфному типу:
3 :: ∀ A . ( A , int ) → ( A , int , int) = ∀ B. B → ( B , интервал)
Таким образом, окончательный тип выражения становится:
2 3 :: ∀ . ( A ) → ( A , интервал, интервал)
Проделав такой же процесс умножения, мы получим:
2 3 :: ∀ . ( ) → ( , Int, Int) × :: ∀ B . ( Б , Int, Int) → ( B , INT) A = B 2 3 × :: ∀ . ( А ) → ( А , целое)
Это правильно: выражение «2 3 ×» не требует ввода и дает одно целое число. Ух! Для проверки работоспособности обратите внимание, что эквивалентная функция «6» имеет тот же тип, что и «2 3 ×»:
6 :: ∀ . ( А ) → ( А , целое)
Итак, конкатенативные языки уже дают нам то, чего обычно не могут прикладные функциональные языки: мы действительно можем возвращать несколько значений из функции, а не только кортежи. А благодаря полиморфизму стека у нас есть единообразный способ составления функций разных типов, поэтому поток данных в наших программах не затмевается, так сказать, водопроводом.
♦ ♦ ♦
Крутые вещи
В приведенном выше примере мы работали слева направо, но, поскольку композиция ассоциативна, вы можете делать это в любом порядке. С математической точки зрения ( f ∘ g ) ∘ h = f ∘ ( g ∘ h ). Так же, как «2 3 ×» содержит «2 3», функцию, возвращающую два целых числа, она также содержит «3 ×», функцию, которая трижды возвращает свой аргумент:
3 × :: (число) → (число)
(С этого момента я буду опускать бит ∀ в сигнатурах типов, чтобы их было легче читать.)
Итак, мы уже можем тривиально представить частичное приложение функции. Но на самом деле это огромная победа с другой стороны. Аппликативные языки должны иметь определенную ассоциативность для приложения функций (почти всегда слева направо), но здесь мы свободны от этого ограничения. Компилятор для статически типизированного конкатенативного языка может буквально:
Разделите программу на произвольные сегменты
Скомпилировать каждый сегмент параллельно
Составьте все сегменты в конце
Это невозможно сделать ни с одним другим языком. При конкатенативном программировании параллельный компилятор - это старый добрый map-reduce!
Поскольку все, что у нас есть, - это функции и композиция, конкатенативная программа представляет собой единственную функцию - обычно нечистую с побочными эффектами, но это ни в коем случае не является обязательным требованием. (Вы можете представить себе чистый, ленивый конкатенативный язык с управлением побочными эффектами в духе Haskell.) Поскольку программа - это всего лишь функция, вы можете думать о составлении программ таким же образом.
Это основная причина того, что конвейеры Unix настолько мощны: они образуют рудиментарный язык конкатенативного программирования на основе строк. Вы можете отправить вывод одной программы в другую ( |); отправлять, получать и перенаправлять несколько потоков ввода-вывода ( n<, 2&>1); и больше. В конце концов, конкатенативная программа - это поток данных от начала до конца. И снова именно поэтому конкатенативная композиция записывается в «обратном» порядке - потому что на самом деле она идет вперед :
+---+
| 2 |
+---+
|
| +---+
| | 3 |
| +---+
| |
V V
+---------+
| * |
+---------+
|
V
♦ ♦ ♦
Реализация
До сих пор я сознательно придерживался высокоуровневых терминов, относящихся ко всем конкатенативным языкам, без каких-либо подробностей о том, как они на самом деле реализованы. Одна из замечательных особенностей конкатенативных языков заключается в том, что, хотя они по своей сути довольно функциональны, они также имеют очень простую и эффективную императивную реализацию. Фактически, конкатенативные языки являются основой многих вещей, которые вы используете каждый день:
Java Virtual Machine на компьютере и мобильном телефоне
CPython байткод интерпретатор , что полномочия BitTorrent, Dropbox, и YouTube
Язык описания страниц PostScript, на котором работают многие принтеры мира
Язык Forth , с которого все началось, который до сих пор пользуется популярностью во встроенных системах
Тип конкатенативной функции сформулирован так, что она принимает любое количество входов, использует только самые верхние из них и возвращает неиспользованный вход, за которым следует фактический выход. Эти функции, по сути, работают со структурой данных, подобной списку, которая позволяет удалять и вставлять только с одного конца. И любой достойный программист может сказать вам, как называется эта структура.
Это стопка. Ага. Просто стопка.
Рассмотрим информацию, передаваемую между функциями в выражении «2 3 × 4 5 × +», которое, если вы не знаете свой постфикс, равно (2 × 3 + 4 × 5):
Функция Вывод
()
2 (2)
3 (2, 3)
× (6)
4 (6, 4)
5 (6, 4, 5)
× (6, 20)
+ (26)
Двигаясь слева направо в выражении, всякий раз, когда мы встречаем «значение» (помните: самовозвратная функция с нулевым значением), мы помещаем его результат в стек. Всякий раз, когда мы сталкиваемся с «оператором» (ненулевой функцией), мы извлекаем его аргументы, выполняем вычисление и отправляем его результат. Другое название постфикса - обратная польская нотация , которая добилась большого успеха на рынке калькуляторов на каждом калькуляторе HP, проданном в период с 1968 по 1977 год, а также во многих последующих.
Таким образом, конкатенативный язык - это функциональный язык, который не только прост, но и тривиален для эффективного выполнения, так что большинство языковых виртуальных машин по сути конкатенативны. x86 в значительной степени полагается на стек для локального состояния, поэтому даже программы на C имеют в себе некоторую конкатенативность, хотя машины x86 основаны на регистрах.
Кроме того, несложно произвести некоторые очень умные оптимизации, которые в конечном итоге основаны на простом сопоставлении и замене шаблонов. Фактор компилятор использует эти принципы для создания очень эффективного кода. Виртуальные машины JVM и CPython, основанные на стеке, также выполняют и оптимизируют конкатенативные языки, поэтому парадигма далеко не неизучена. Фактически, значительная часть всех исследований по оптимизации компилятора, которые когда-либо проводились, касалась виртуальных стековых машин.
♦ ♦ ♦
Бесточечные выражения.
Хорошим стилем функционального программирования считается написание функций в безточечной форме без ненужного упоминания переменных ( точек ), над которыми работает функция. Например, « f x y = x + y » можно записать как « f = (+)». Более ясно и менее однообразно сказать « f - это функция сложения», чем « f возвращает сумму своих двух аргументов».
Что еще более важно, более осмысленно писать, что такое функция , а не то, что она делает , а функции без точек более лаконичны, чем так называемые «точечные». По всем этим причинам безточечный стиль обычно считается хорошей вещью ™.
Однако, если функциональные программисты действительно считают, что бесточечный стиль идеален, им не следует использовать прикладные языки! Допустим, вы хотите написать функцию, которая сообщит вам количество элементов в списке, удовлетворяющих предикату. В Haskell, например:
countWhere :: (a -> Bool) -> [a] -> Int
countWhere predicate list = length (filter predicate list)
Это довольно просто, даже если вы не слишком знакомы с Haskell. countWhereвозвращает lengthсписок, который вы получаете, когда вы filterизвлекаете элементы, listкоторые не удовлетворяют predicate. Теперь мы можем использовать это так:
countWhere (>2) [1, 2, 3, 4, 5] == 3
Мы можем написать это двумя способами в бессмысленном стиле, опуская predicateи list:
countWhere = (length .) . filter
countWhere = (.) (.) (.) length filter
Но смысл странного многократного самостоятельного применения оператора композиции ( .) не обязательно очевиден. Выражение - (.) (.) (.)эквивалентно (.) . (.)инфиксному синтаксису - представляет функцию, составляющую унарную функцию ( length) с двоичной функцией ( filter). Иногда пишут этот тип композиции .:, и этого можно ожидать:
(.:) :: (c -> d) -> (a -> b -> c) -> a -> b -> d
(.:) = (.) . (.)
countWhere = length .: filter
Но что мы на самом деле здесь делаем? В аппликативном языке мы должны преодолеть некоторые препятствия, чтобы получить основные конкатенативные операторы, которые нам нужны, и заставить их выполнять проверку типов. При реализации композиции с точки зрения приложения мы должны явно реализовать каждый тип композиции.
В частности, не существует единого способа составления функций с разным количеством аргументов или результатов. Для того, чтобы даже приблизиться к тому , что в Haskell, вы должны использовать curryи uncurryфункцию явно обернуть вещи в кортежи. Независимо от того, что вам нужны разные комбинаторы для составления функций разных типов, потому что в Haskell нет стекового полиморфизма для аргументов функции, и он по сути не может.
Написание бесточечных выражений требует конкатенативной семантики, что просто неестественно для прикладного языка. Теперь сравните конкатенативный пример:
define countWhere [filter length]
(1, 2, 3, 4, 5) [2 >] countWhere
Это почти до боли дословно: «подсчитать количество элементов в списке, соответствующих предикату, значит отфильтровать его и взять длину». В конкатенативном языке переменные вообще не нужны, потому что все, что вы делаете, это создаете машину для передачи данных:
+-----------------+
| (1, 2, 3, 4, 5) |
+-----------------+
|
| +-------+
| | [2 >] |
| +-------+
| |
+---|-----------------|-----+
| | countWhere | |
| V V |
| +-----------------------+ |
| | filter | |
| +-----------------------+ |
| | |
| V |
| +--------+ |
| | length | |
| +--------+ |
| | |
+---|-----------------------+
|
V
Когда вы строите такую диаграмму, просто следуйте нескольким простым правилам:
Каждый блок - это одна функция
Блок занимает столько столбцов, сколько необходимо для его входов или выходов, в зависимости от того, что больше
Добавляя блок, поместите его в крайний правый столбец:
Если это не требует ввода, добавьте столбец
Если не хватает стрелок, чтобы соответствовать блоку, программа плохо типизирована
♦ ♦ ♦
Цитаты.
Обратите внимание на использование скобок для предиката [2>] в предыдущем примере? Помимо композиции, функцией, завершающей конкатенативный язык, является цитирование , которое позволяет отложить композицию функций. Например, «2>» - это функция, которая возвращает, превышает ли ее аргумент 2, а [2>] - это функция, возвращающая «2>».
Именно в этот момент мы переходим к мета. В то время как простая композиция позволяет нам создавать описания машин потока данных, цитаты позволяют нам создавать машины, которые работают с описаниями других машин . Цитирование устраняет различие между кодом и данными простым и безопасным для типов способом.
«Фильтрующая» машина, упомянутая ранее, принимает схемы для машины, которая принимает значения списка и возвращает логические значения, и фильтрует список в соответствии с инструкциями в этих схемах. Вот его подпись:
filter :: (список T , T → bool) → (список T )
С этим можно делать все, что угодно. Вы можете написать функцию, которая применяет цитату к некоторым аргументам, не зная, что это за аргументы:
применяются :: ∀ A B . ( А , А → В ) → ( В )
Вы можете написать функцию для объединения двух цитат в новую:
Сотрозе :: ∀ Б С . ( A → B , B → C ) → ( A → C )
И вы можете написать так, чтобы преобразовать функцию в цитату, которая ее возвращает:
цитата :: ( T ) → (() → T )
♦ ♦ ♦
Темная сторона
Допустим, вы хотите преобразовать математическое выражение в конкатентивную форму:
f x y z = y 2 + x 2 - | y |
Здесь всего понемногу: он несколько раз упоминает один из своих входов, порядок переменных в выражении не соответствует порядку входов, и один из входов игнорируется. Итак, нам нужна функция, которая дает нам дополнительную копию значения:
dup :: ( Т ) → ( Т , Т )
Функция, которая позволяет нам переупорядочивать наши аргументы:
своп :: ( Т 1 , Т 2 ) → ( Т 2 , Т 1 )
И функция, позволяющая игнорировать аргумент:
падение :: ( T ) → ()
Из основных функций, которые мы определили до сих пор, мы можем создать некоторые другие полезные функции, например, функцию, которая объединяет два значения в цитату:
join 2 :: ( T 1 , T 2 ) → (() → ( T 1 , T 2 ))
join 2 = обмен котировками обмен цитатами составить
Или функция, которая поворачивает свои три аргумента влево:
rot 3 :: ( T 1 , T 2 , T 3 ) → ( T 2 , T 3 , T 1 )
rot 3 = присоединиться 2 обменять цитату составить применить
И, эй, благодаря цитатам, также легко объявить свои собственные управляющие структуры:
define true [[drop apply]] # Apply the first of two arguments.
define false [[swap drop apply]] # Apply the second of two arguments.
define if [apply] # Apply a Boolean to two quotations.
И использовать их, как- на самом деле, просто это -он имеет регулярную функцию:
["2 is still less than 3."] # "Then" branch.
["Oops, we must be in space."] # "Else" branch.
2 3 < # Condition.
if print # Print the resulting string.
Эти конкретные определения для trueи falseбудут знакомы любому , кто использовал булевы в Х-исчислении. Логическое значение - это цитата, поэтому оно ведет себя как обычное значение, но содержит двоичную функцию, которая выбирает одну ветвь и отбрасывает другую. «Если-то-еще» - это просто применение этой цитаты к конкретным ветвям.
В любом случае, возвращаясь к математике, мы уже знаем тип нашей функции ((int, int, int) → (int)), нам просто нужно понять, как туда добраться. Если мы построим диаграмму того, как данные проходят через выражение, мы можем получить следующее:
+---+ +---+ +---+
| x | | y | | z |
+---+ +---+ +---+
x y z
| | |
| | V
| | +------+
| | | drop |
| | +------+
| V
| +----------+
| | dup |
| +----------+
| y y
| | |
| | V
| | +----------+
| | | dup |
| | +----------+
| | y y
| | | |
| | V V
| | +----------+
| | | * |
| | +----------+
| | y^2
| | |
| V V
| +----------+
| | swap |
| +----------+
| y^2 y
| | |
| | V
| | +-----+
| | | abs |
| | +-----+
| | |y|
| | |
V V V
+-----------------+
| rot3 |
+-----------------+
y^2 |y| x
| | |
| | V
| | +----------+
| | | dup |
| | +----------+
| | x x
| | | |
| | V V
| | +----------+
| | | * |
| | +----------+
| | x^2
| | |
| V V
| +----------+
| | swap |
| +----------+
| x^2 |y|
| | |
| V V
| +----------+
| | - |
| +----------+
| x^2-|y|
| |
V V
+----------+
| + |
+----------+
y^2+x^2-|y|
|
V
Итак, нашу последнюю функцию можно записать:
f = drop dup dup × перестановка abs rot 3 dup × перестановка - +
Ну… это отстой.
♦ ♦ ♦
Более легкое замечание.
Вы только что увидели одну из основных проблем конкатенативного программирования: у каждого языка есть свои сильные и слабые стороны, но большинство разработчиков языков будут лгать вам насчет последнего. Написание, казалось бы, простых математических выражений может быть трудным и неинтуитивным, особенно с использованием только тех функций, которые мы видели до сих пор. Это раскрывает всю основную сложность выражения, которую мы привыкли передавать компилятору.
Factor обходит это, вводя средство для локальных переменных с лексической областью видимости. Некоторые вещи проще писать с именованным состоянием, чем кучей перетасовки стека. Однако в подавляющем большинстве программ математические выражения не преобладают, поэтому на практике эта функция не очень часто используется:
«Из 38 088 определений слов и методов в исходном коде Factor и его среде разработки на момент написания этой статьи 310 были определены с именованными параметрами». - Фактор: язык программирования на основе динамического стека.
Однако одной из самых сильных сторон конкатенативных языков является их способность рефакторировать сложные выражения. Поскольку каждая последовательность терминов - это просто функция, вы можете напрямую вытащить часто используемый код в его собственную функцию, даже не переписывая что-либо. Как правило, не нужно переименовывать переменные и управлять состоянием.
Таким образом, на практике множество выражений можно реорганизовать с помощью широкого набора удобных функций, которые обычно попадают в стандартную библиотеку. После некоторого рефакторинга это математическое выражение может выглядеть так:
квадрат = dup ×
f = падение [квадрат] [абс] би - [квадрат] провал +
Что не так уж плохо и хорошо читается: разница между квадратом и абсолютным значением второго аргумента плюс квадрат первого. Но даже это описание показывает, что наш математический язык эволюционировал как прикладной. Иногда лучше просто придерживаться традиции.
♦ ♦ ♦
Куда отсюда
Итак, вы поняли суть, и потребовалось всего несколько десятков упоминаний слова «конкатенативный», чтобы добраться до нее. Надеюсь, вы не страдаете смысловым пресыщением.
Вы видели, что конкатенативное программирование - это такая же парадигма, как и любая другая, с настоящим определением и своими плюсами и минусами:
Конкатенативные языки просты и последовательны («все есть»)
Они поддаются программированию потока данных
Языки стека хорошо изучены и имеют хорошую производительность
Вы можете легко свернуть собственные контрольные структуры
Все написано бессмысленно (хорошо это или плохо)
Если вы хотите попробовать зрелый, практичный конкатенативный язык, загляните в Factor и в официальный блог его создателя Славы Пестова. Также см. Cat для получения дополнительной информации о статической типизации на конкатенативных языках.
Я уже некоторое время лениво работал над небольшим конкатентивным языком под названием Kitten . Он динамически типизирован и компилируется в C, поэтому вы можете запускать его где угодно. Мне нужен был язык, который я мог бы использовать для сайта на общем хосте, где установка компиляторов меня раздражала. Это показывает вам степень моих языковых фанатиков - я лучше потрачу часы на написание языка, чем двадцать минут на выяснение того, как установить GHC на Bluehost.
В любом случае, реализация едва ли завершена, чтобы можно было поиграть. Не стесняйтесь просматривать источник, пробовать его и предлагать отзывы. Для его создания вам понадобятся GHC и GCC, и я полагаю, что он лучше всего работает в Linux или Unix, но не должно быть особо ужасной несовместимости.
Это также хорошее время, чтобы упомянуть, что я работаю над более серьезным языком под названием Magnet, о котором я упоминал в своей последней статье о том, как происходит программирование . Он в основном конкатенативный, но для удобства имеет прикладной синтаксис и в значительной степени опирается на двойную магию сопоставления с образцом и обобщенных алгебраических типов данных. Черт, половина причины, по которой я написал эту статью, заключалась в том, чтобы предоставить основу для Magnet. Так что ждите больше статей об этом.
Изменить (20 апреля 2013 г.) Приведенная выше информация больше не точна. Котенок сейчас переписывается; работа, которая была проделана над Magnet, была включена. Kitten теперь статически типизирован и до завершения компиляции интерпретируется.
И это о нем. Как всегда, не стесняйтесь писать мне на evincarofautumn@gmail.com, чтобы подробно рассказать о чем угодно. Удачного кодирования!
По Джон Парди в 12:02 AM Отправить по электронной почте BlogThis! Поделиться в Twitter Поделиться в Facebook Поделиться в Pinterest
Теги: Вычисления , Конкатенативный , Котенок , Язык , Магнит , Программирование , Веб
P.S. После статьи есть ещё некоторое обсуждение в комментариях.