LINUX.ORG.RU

[ФП][срач] Язык программирования Pure


2

4

Pure - динамически типизированный функциональный язык программирования с моделью исполнения, основанной на идее «term rewriting».

  • Синтаксис, бликий к Haskell (включая карринг, срезы, лямбды, сопоставление с образцом, list comprehensions и «as» patterns);
  • Поддерживает модель ленивости, основанную на продолжениях и заимствованную из Alice ML;
  • Допускает функции с побочными эффектами, опциональную аннотацию типов, интерфейсные типы
  • Поддержка рациональных, комплексных чисел, встроенный RegEx;
  • Содержит спектр встроенных структур данных, таких как: списки, туплы, векторы, матрицы и ленивые последовательности;
  • Интеграция с GSL;
  • Поддерживает полноценную систему гигиенических макросов;
  • Лёгкий FFI с сишными библиотеками;
  • Реализация под LLVM под GNU/Linux, Mac OS X, FreeBSD и Windows;
  • Из коробки поддержка компиляции в нативный код;
  • В комплекте идёт набор батареек для разнообразных нужд.

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

The Pure interpreter is able to achieve very good performance, offering execution speeds in the same ballpark as good Lisp interpreters. It seems to be one of the fastest implementations of term rewriting as a programming language right now, and is certainly good enough for most programming tasks except maybe the most demanding number crunching applications (and even these can be tackled by interfacing to Fortran or C).

Язык активно развивается, последняя версия документации датирована 8 января, автор постоянно пилит своё детище, активно идёт на контакт и охотно принимает и рассматривает любые предложения.

Ссылка на страницу проекта: http://code.google.com/p/pure-lang/
Ссылка на документацию (pdf): http://docs.pure-lang.googlecode.com/hg/puredoc.pdf
Ссылка на пример полной реализации АВЛ-деревьев: http://pure-lang.googlecode.com/hg/pure/examples/avltree.pure
Репозиторий (лицензия LGPLv3): hg clone https://code.google.com/p/pure-lang/

★★★★★

Ответ на: комментарий от anonymous

мне хочется сгенерировать выражение

С точки зрения абстрактного синтаксиса между [1 + 2 + 3] и (+ 1 2 3) просто нет разницы - нет в разницы в лиспах, нет разницы в бедном core основанного на LC.

как это сделать при помощи квазицитирования

Но если на уровне конкретного синтаксиса в хаскеле (вот кстати HsSyn != Core, в отличии от лиспов): \x y z -> [| x + y + z |].

quasimoto ★★★★
()
Ответ на: комментарий от quasimoto

С точки зрения абстрактного синтаксиса между [1 + 2 + 3] и (+ 1 2 3) просто нет разницы - нет в разницы в лиспах, нет разницы в бедном core основанного на LC.

Блять, да напиши ты код, который это сделает. Нахер ты уже 5 раз отписки на абзац хреначишь вместо одной строчки кода?

Но если на уровне конкретного синтаксиса в хаскеле (вот кстати HsSyn != Core, в отличии от лиспов): \x y z -> [| x + y + z |].

Так, ты не понял немного, еще раз - есть оператор op и список аргументов args, дальше при помощи квазицитирвоания блаблабла...

anonymous
()
Ответ на: комментарий от anonymous

Это что?

Спроси общелисперов (у них много хитрых макросов вроде iterate или loop) - не нравится непарные выражения у bad-let? Ну напиши функцию которая будет делать пары и сделай `(let ,(make-pairs binds) ,@body) (kindergarten graduated level).

quasimoto ★★★★
()
Ответ на: комментарий от quasimoto

Это был риторический вопрос. Подразумеваемый ответ - кривая отписка. Еще раз - напиши код который делает то, что я прошу. Не больше и не меньше.

Ну напиши функцию которая будет делать пары и сделай `(let ,(make-pairs binds) ,@body) (kindergarten graduated level).

Ну так давай, напиши и сделай. Мы посмотрим на результат и до тебя тогда, надеюсь, дойдет, почему в ЯП с негомоиконным синтаксисом макросы неприменимы. Если бы ты до этого пытался в лиспе том же макросы писать - ты бы уже и так знал почему, т.к. даже там иногда приходится плеваться и городить костыли из-за подобной вот хрени. И если такие костыли придется на _каждом_ шагу лепить - то так макросы писать нельзя. Вот нельзя и все. Заебет (хотя общебляди пишут, конечно, но на то они и общебляди, чтобы жрать говно и радоваться).

anonymous
()
Ответ на: комментарий от anonymous

есть оператор op и список аргументов args, дальше при помощи квазицитирвоания блаблабла...

Ты не сказал что такое op. Операция моноида?

genRightFold elements identity operation =
  foldr (\x xs -> [| x `operation` $xs |]) identity elements

genLeftFold elements identity operation =
  foldl (\xs x -> [| x `operation` $xs |]) identity elements

Если это правда операция моноида (типа (+), (*) или (++)), то она ассоциативна и genRightFold == genLeftFold == genFold.

quasimoto ★★★★
()
Ответ на: комментарий от quasimoto

Если это правда операция моноида (типа (+), (*) или (++))

Это просто какая-то бинарная операция, она может быть как ассоциативной так и нет, твоя ф-я должна работать во всех случаях. Жду реализации. Да, никаких таких identity, функция принимает только оператор и аргументы, естественно. Но вообще, даже если считать твое решение правильным, было:

(op args ...)

cтало:

foldr (\x xs -> [| x `operation` $xs |]) identity elements

А теперь, мой друг, учти, что в среднем макросе такие формы раз эдак 20-30 встретятся. То есть даже в гомоиконном случае будет выражение на пару-тройку строк, которое может выглядеть не просто, у тебя же будет 20-30 строк вот такого вот не имеющего ничего общего с декларативным описанием говна:

foldr (\x xs -> [| x `operation` $xs |]) identity elements

Мне еще надо объяснять, почему в ЯП с пересахаренным синтаксисом типа хаскеля макросы неприменимы, или так дошло?

anonymous
()
Ответ на: комментарий от anonymous

Еще раз - напиши код который делает то, что я прошу. Не больше и не меньше.

То что там было в самом начале - (let (a 1 b 2 b 3) ...)?

(defmacro bad-let (bad-bindings &body body)
  (labels
      ((pairs (list)
         (if (< 2 (length list))
             `((,(car list) ,(cadr list)) ,@(pairs (cddr list)))
             `(,list))))
    `(let ,(pairs bad-bindings)
       ,@body)))

(macroexpand-1 '(bad-let (a 1 b 2 c 3) (+ a b c)))
(LET ((A 1) (B 2) (C 3))
  (+ A B C))

такой читаемый и понятный этот код!1 :)

quasimoto ★★★★
()
Ответ на: комментарий от anonymous

Да, никаких таких identity, функция принимает только оператор и аргументы, естественно.

Я как-то делал constant folding арифметики для SBCL (там макро-подобные define-source-transform), без identity нет никакого смысла писать такое макро-преобразование - что оно вернёт если args == nil? Очевидно - identity, (op '+) == 0, (op '*) == 1, (op 'append) == nil и т.п.

(op args ...)

cтало

Нет, это вызов макроса, стало - genFold [args ...] 0 (+).

А

foldr (\x xs -> [| x `operation` $xs |]) identity elements

это определение макроса op, вот ты на схеме уложишься в одну строчку?

quasimoto ★★★★
()
Ответ на: комментарий от quasimoto

такой читаемый и понятный этот код!1 :)

Угу, вот именно. Именно такой код получаем с негомоиконным синтаксисом. С гомоиконным синтаксисом (уже приводил):

(define-syntax-rule (bad-let ((id expr) ...) body ...)
  (let ((id expr ...)) body ...))

чувствуешь разницу?

anonymous
()
Ответ на: комментарий от quasimoto

без identity нет никакого смысла писать такое макро-преобразование - что оно вернёт если args == nil?

Ошибку оно вернет. А мы считаем тут, что проверка на непустоту уже произведена.

это определение макроса op, вот ты на схеме уложишься в одну строчку?

Уложусь, конечно (точно так же). Но на схеме у меня гомоиконный синтаксис, мне _не надо_ укладываться в одну строчку. Я просто вместо

foldr (\x xs -> [| x `operation` $xs |]) identity elements

пишу:

(op args ...)

ясно, да? А ты так не можешь. Вот в чем разница.

Нет, это вызов макроса, стало - genFold [args ...] 0 (+).

Нет, это не вызов макроса - это его тело. Там, где мне надо сгенерировать подобнцю форму я пишу (op args ...) или `(,op ,@args), а ты пишешь foldr (\x xs -> [| x `operation` $xs |]) identity elements

anonymous
()
Ответ на: комментарий от quasimoto

А разве в CL не гомоиконный синтаксис?

гомоиконный, но там нету средств для его обработки (в scheme есть). Средства обработки - это уже как раз часть макросистемы. Но если синтаксис негомоиконный, то и средств обработки не будет :) Либо они на порядок сложнее.

anonymous
()
Ответ на: комментарий от anonymous

Ошибку оно вернет. А мы считаем тут, что проверка на непустоту уже произведена.

Пусть у нас будет такая форма - (+ 1 a 2 b 3 c (*)) сворачиватель констант как раз является разновидность такой op и он должен свернуть (*) в 1, а всё вместе в (+ 7 a b c).

Короче, то что ты просил это, натурально, свёртка в моноиде.

ясно, да? А ты так не можешь. Вот в чем разница.

Понял. Ну насчёт высокоуровневых rules из схемы я знаю - аналогов такого в ML-ях не видел.

quasimoto ★★★★
()
Ответ на: комментарий от quasimoto

Короче, то что ты просил это, натурально, свёртка в моноиде.

Хотя, если операция не ассоциативна, то это лево-ассоциативная свёртка в магме (в отличии от моноида, где максимум 1 разнозначная свёртка, в магме их максимум n!) - identity нет, при args = nil свёртка не определена.

quasimoto ★★★★
()
Ответ на: комментарий от anonymous

1. никакой разницы особой (так чтобы прям сильно заметно было) при разборе подобных выражений нет

Если писать в десять раз больше кода/использовать в десять раз более навороченное апи к парсеру - это «особой разницы нет», то ок, конечно.

один раз ты пишешь правило по которому эта конструкция разбирается, и это правило будет лишь немногим сложнее чем то которое используется для первого случая, а далее тебе - и так, и так - всё равно парсить выражение

так что там нет никаких порядков

Но не нужно - потому что то, что в пару строк пишется для языка с гомоиконным синтаксисом, тут будет превращаться в кучу рид-онли лапшекода.

синтаксис - дело привычки, не более того, и, если не извращаться, как в своё время с коболами всякими, где не было зарезервированных слов, а каждый конкретный случай выводился из контекста - то жить можно, и не кашлять

shty ★★★★★
()
Ответ на: комментарий от anonymous

Зато их можно собирать и разбирать на уровне AST:

О чем и речь. Разобрать то _можно_ но какой ценой?

а что там с ценой не так?

-- LetE [ValD (VarP x_0) (NormalB (LitE (IntegerL 1))) [],ValD (VarP y_1) (NormalB (LitE (IntegerL 2))) []] (InfixE (Just (VarE x_0)) (VarE GHC.Num.+) (Just (InfixE (Just (VarE y_1)) (VarE GHC.Num.+) (Just (LitE (IntegerL 0))))))

И что это? Ты можешь с первого взгляда определить что это вообще за хрень, что делает и как работает?

в эту игру можно играть вдвоём, давай я тебе вообще сейчас пачку машинных кодов выкачу, и что это докажет?

shty ★★★★★
()
Ответ на: комментарий от quasimoto

Без identity:

gen :: Exp -> [Exp] -> Exp
gen f xs = foldl1 (\a b -> InfixE (Just a) f (Just b)) xs

test xs = do
  f  <- [| (+) |]
  xs <- mapM (\x -> [| x |]) xs
  return $ gen f xs

-- > runQ $ test ([] :: [Int])
-- *** Exception: Prelude.foldl1: empty list

-- > runQ $ test [1]
-- LitE (IntegerL 1)

-- > runQ $ test [1, 2, 3]
-- InfixE (Just (InfixE (Just (LitE (IntegerL 1))) (VarE GHC.Num.+) (Just (LitE (IntegerL 2))))) (VarE GHC.Num.+) (Just (LitE (IntegerL 3)))

квазицитирование не осилил.

quasimoto ★★★★
()
Ответ на: комментарий от shty

Кстати, это (Exp) выглядит некрасиво только потому что инстансы Show не написаны с pretty-printer-ом (для целей копания в аст), а то бы это выглядела как тот хаскель-код, который генерируется. Не трудно, при желании, сделать, чтобы по

(foo :: Q Exp) >>= pprint

печатался нормальный хаскельный код (с точностью до уникальных id при именах переменных).

quasimoto ★★★★
()
Ответ на: комментарий от shty

хотя, если подумать, я наверное отчасти понимаю - он считает что лисп driven by magic, на самом же деле всё несколько прозаичнее :)

shty ★★★★★
()
Ответ на: комментарий от anonymous

пишу: (op args ...)

А если нужно право-ассоциативно?

quasimoto ★★★★
()
Ответ на: комментарий от quasimoto

Понял. Ну насчёт высокоуровневых rules из схемы я знаю - аналогов такого в ML-ях не видел.

Ну да, и проблема в том, что в негомоиконном ЯП такие rules реализовать нельзя. Но ты это сам уже понял, вроде как.

anonymous
()
Ответ на: комментарий от quasimoto

Хотя, если операция не ассоциативна, то это лево-ассоциативная свёртка в магме (в отличии от моноида, где максимум 1 разнозначная свёртка, в магме их максимум n!) - identity нет, при args = nil свёртка не определена.

Ну тут не важна ассоциативность, мы должны получить [1 + 2 + 3 ...], при чем тут ассоциативность?

anonymous
()
Ответ на: комментарий от shty

один раз ты пишешь правило по которому эта конструкция разбирается

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

а далее тебе - и так, и так - всё равно парсить выражение

Вопрос в том - как парсить. Можно руками разбирать АСТ, а можно простыми паттернами, что намного короче и понятнее.

синтаксис - дело привычки, не более того, и, если не извращаться

Речь не о том, речь о том, что для выражения языка с более простой грамматикой проще как разбирать, так и генерировать. Это очевидно утверждение, нет?

anonymous
()
Ответ на: комментарий от shty

в эту игру можно играть вдвоём, давай я тебе вообще сейчас пачку машинных кодов выкачу, и что это докажет?

и докажешь, что машинные коды руками генерят только ебланы вроде тебя. О чем я и говорил изначально.

anonymous
()
Ответ на: комментарий от quasimoto

квазицитирование не осилил.

Ну да, построение АСТ руками :)

А с квазицитированием - Ph.D, как я и говорил. Между тем, единственный естественный способ генерации макро-форм - именно квазицитирование, любая попытка генерации АСТ напрямую резко усложняет написание макроса.

anonymous
()
Ответ на: комментарий от quasimoto

Ну согласись, что это выглядит на порядок сложнее, чем (op args ..). С этим спорить не станешь? :)

anonymous
()
Ответ на: комментарий от shty

проблема в том, что вместо (op args ...) надо писать:

gen f = foldl1 (\a b -> [| $f $a $b |])
test = gen [| (+) |] $ map (\x -> [| x |]) ([1, 2, 3] :: [Int])

И никаких driven by magic, тащем-то.

anonymous
()
Ответ на: комментарий от anonymous

Ну тут не важна ассоциативность, мы должны получить [1 + 2 + 3 ...], при чем тут ассоциативность?

(1 + 2 + 3) это же сахар для (+ (+ 1 2) 3) = (+ 1 (+ 2 3)). Если '+ в (+ 1 2 3) ещё можно считать тернарной операцией, то инфикс - бинарная на множестве, уже магма (пусть замкнута), если ассоциативна, то моноид, и количество возможных равнозначных свёрток резко сокращается до единицы.

Ну да, построение АСТ руками :)

Тут такая теория - алгебраические типы принято разбирать петтерн-матчингом и собирать с помощью конструкторов и комбинаторов. На AST представляемый такими типами (и разные DSL, и AST целевого языка) смотрят как на обычный же ADT (которым он, технически, и является), поэтому также разбирают паттерн-матчингом и собирают конструкторами (AST руками) или комбинаторами (как в этих примерах с fold). При этом какой-то более высокий уровень на котором разбор будет осуществляться тем же (возможно, адаптированным) паттерн-матчингом, а сбор декларативными правилами (атрибутная грамматика), это... просто более высокий уровень :)

Тут нужно иметь ввиду, что в хаскельном варианте мета-системы «макросы» используются для DSL-ей верхнего уровня, то есть для compile-time трансляции вовсе чужого синтаксиса в хаскель (примеры - multiline strings, interpolation, deriving binary, yesod routes, hamlet templates). Ни в коем случае не для eDSL, который в хаскеле (и в ML-ях вообще) это просто сами ADT и функции их обработки (runtime-интерпретируемый eDSL). Компилируемого и гомоиконного eDSL нет вообще.

А с квазицитированием

С квазицитирование всё-таки можно, но там оно ограничено - сплайсы в декларациях не работаю, например. Ну и сильно типизированно (тоже ограничение).

Ну согласись, что это выглядит на порядок сложнее, чем (op args ..). С этим спорить не станешь? :)

А приведи полный аналогичный код? Точнее, два варианта - лево-ассоциативный и право- тоже. Хотя, всё равно это будет генератор для eDSL, тогда как в хаскеле - часть генератора который служит для DSL -> хаскель.

quasimoto ★★★★
()
Ответ на: комментарий от anonymous

а далее тебе - и так, и так - всё равно парсить выражение

Вопрос в том - как парсить. Можно руками разбирать АСТ, а можно простыми паттернами, что намного короче и понятнее.

что значит руками разбирать AST... ты это делаешь руками? тогда понятно почему тебе страшно (хотя всё равно не очень), может тебе потренировать в написании деревьев для начала?

синтаксис - дело привычки, не более того, и, если не извращаться

Речь не о том, речь о том, что для выражения языка с более простой грамматикой проще как разбирать, так и генерировать. Это очевидно утверждение, нет?

конечно очевидное, и здесь я с тобой согласен, и об этом тебе чуть выше написал, я только не согласен с тобой в оценке сложности

shty ★★★★★
()
Ответ на: комментарий от anonymous

и докажешь, что машинные коды руками генерят только ебланы вроде тебя.

увы, вынужден тебя огорчить, дело в том что только одарённые создания навроде тебя думают, что машинные коды иначе кроме как руками сгенерить нельзя :)

shty ★★★★★
()
Ответ на: комментарий от anonymous

любая попытка генерации АСТ напрямую резко усложняет написание макроса

почему?

shty ★★★★★
()
Ответ на: комментарий от quasimoto

(1 + 2 + 3) это же сахар для (+ (+ 1 2) 3) = (+ 1 (+ 2 3)). Если '+ в (+ 1 2 3) ещё можно считать тернарной операцией, то инфикс - бинарная на множестве, уже магма (пусть замкнута), если ассоциативна, то моноид, и количество возможных равнозначных свёрток резко сокращается до единицы.

Это все неважно. Мы генерируем выражение [1 + 2 + 3], а рассахаривает его уже пусть компилятор.

Тут такая теория - алгебраические типы принято разбирать петтерн-матчингом и собирать с помощью конструкторов и комбинаторов.

То есть в ЯП с АТД нормально макросы использовать нельзя. Ок.

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

А для негомоиконного ЯП такое сделать просто нельзя. Не существует для него этого высокого уровня. Либо сам язык паттернов будет жутко нагруженный и неудобный.

С квазицитирование всё-таки можно, но там оно ограничено - сплайсы в декларациях не работаю, например. Ну и сильно типизированно (тоже ограничение).

Нельзя, в данном случае на чистом квазицитировании нифига не выйдет без фолдов/мапов и т.п. Ну или резко усложняем ЯП паттернов вплоть до того, что уже в декларативных правилах будет получаться такая же лапша как и при ручном конструировании АСТ.

А приведи полный аналогичный код?

Это (op args ...) и есть полностью аналогичный код. Или тебе нужен именно код для генерации [1 + 2 + 3]?

Точнее, два варианта - лево-ассоциативный и право- тоже.

Ну, собственно, вариант на хаскеле можно переписать один в один. Ну и можно вместо рассахаренного ((1 + 2) + 3) сгенерить и чистое (1 + 2 + 3), так что при чем тут вообще ассоциативность? У тебя совершенно неверный подход к написанию макросом. Важно именно во что раскрывается макрос (в какую форму), а не что эта форма делает. Семантику мы ей по сути придаем потом (когда-нибудь, может быть).

anonymous
()
Ответ на: комментарий от shty

что значит руками разбирать AST... ты это делаешь руками? тогда понятно почему тебе страшно (хотя всё равно не очень), может тебе потренировать в написании деревьев для начала?

«Руками» - это разбор АТД в хаскеле, например. Ты умеешь по-другому там?

конечно очевидное, и здесь я с тобой согласен, и об этом тебе чуть выше написал, я только не согласен с тобой в оценке сложности

Оценка сложности выше так же приведена - в ЯП с негомоиконным синтаксисом получаем в ~10 раз больше кода, причем кода недекларативного и непонятного. И это _в простейших_ случаях. Я могу, конечно, выбрать более сложный пример, где будут формы строк эдак на 10, а не примитивного (op args ...), сделать?

anonymous
()
Ответ на: комментарий от shty

и кто это писать будет?

Ну вот именно, братюнь. Никто это писать не будет. И не пишет. То есть макросы - неюзабельны (ведь способа решить приведенную задачу без такого вот лапшекода - не существует). О чем я и говорил в самом начале.

anonymous
()
Ответ на: комментарий от anonymous

такой читаемый и понятный этот код!1 :)

Угу, вот именно. Именно такой код получаем с негомоиконным синтаксисом. С гомоиконным синтаксисом (уже приводил):

(define-syntax-rule (bad-let ((id expr) ...) body ...)
  (let ((id expr ...)) body ...))

Я схему не знаю, но мне кажется, что этот код раскрывает

(bad-let ((a 1) (b 2)) body)
в
(let ((a 1 2)) body)
а надо ---
(bad-let (a 1 b 2) body)
в
(let ((a 1) (b 2)) body)
Можно правильный вариант? Или, если этот таки правильный --- неправильный, чтобы увидеть в чём различие. Мне прежде всего любопытно, можно ли без «ручного петушения списков» генерить преобразования чередующихся элементов в нечередующиеся и обратно: (a 1 b 2) <-> ((a 1) (b 2))

Интересно, подобный pattern matching можно перенести в common lisp или есть какие-то принципиальные ограничения?

anonymous
()
Ответ на: комментарий от anonymous

что значит руками разбирать AST... ты это делаешь руками? тогда понятно почему тебе страшно (хотя всё равно не очень), может тебе потренировать в написании деревьев для начала?

«Руками» - это разбор АТД в хаскеле, например.

для меня «руками» - это когда для каждого выражения ты сам должен составлять схему разбора, так вот в хаскеле - это не «руками»

shty ★★★★★
()
Ответ на: комментарий от anonymous

конечно очевидное, и здесь я с тобой согласен, и об этом тебе чуть выше написал, я только не согласен с тобой в оценке сложности

Оценка сложности выше так же приведена

давай ещё раз - я её видел и я с этой оценкой несогласен, с математической т.з. - это очень слабая, неустойчивая, если хочешь, оценка

shty ★★★★★
()
Ответ на: комментарий от anonymous

Дружок,

дружок - это велосипед

это же ты предлагал их руками генерить, а не я.

ты может покажешь где я предлагал руками генрить?

shty ★★★★★
()
Ответ на: комментарий от anonymous

То есть в ЯП с АТД нормально макросы использовать нельзя. Ок.

Cхема - ЯП с АТД, но маросы есть. В языках в которых DSL/eDSL основаны на ADT (так точнее) макросов и гомоиконности вообще может не быть. Например, в хаскеле макросов нет. Есть обычные функции которые которые работают с типами Exp, Dec и т.п. и обычные функции возвращающие тип QuasiQuoter. И используются они для совсем других целей - не для расширений целевого языка (добавления гомоиконного compile-time eDSL), а для встроенных compile-time DSL (например, в yesod - routes сервера, в hamlet - шаблоны) или для негомоиконных compile-time eDSL (пример - deriving binary).

Нельзя, в данном случае на чистом квазицитировании нифига не выйдет без фолдов/мапов и т.п.

Да, без фолдов и мапов нельзя. Я, например, не хотел бы, чтобы нельзя было строить AST конструкторами и комбинаторами.

Но в схеме тоже не получится без фолдов. Всё что выходит за рамки того что умеют паттерны генерируется обычным схемовым кодом.

Или тебе нужен именно код для генерации [1 + 2 + 3]?

Мои две строчки берут цитированную бинарную функцию и цитированный список аргументов и расставляют скобочки (одна слева, другая справа). На самом деле тут вообще нет ничего интересного - это обычные foldl / foldr, работающие с типами (Q Exp), т.е. с цитированными AST.

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

Изначально я сказал, что языку не нужно быть гомоиконным и не нужно отказываться от конкретного синтаксиса, чтобы иметь возможность мета-вычислений. Но ты сказал, что тогда эти вычисления будут «сложными». Очевидно, если в каждую задачу, через раз, совать мета-вычисления, то получится некрасиво. Но если пользоваться ими только по делу, то ничего.

сгенерить и чистое (1 + 2 + 3)

Что такое чистое (1 + 2 + 3) если в языке нет инфикса? Если речь про макрос infix вида (infix 1 + 2 + 3), то он, во-первых, тоже знает про ассоциативность, и, во-вторых, и является тем кто рассахаривает инфикс в префикс. Если в AST языка есть инфикс, то это (infix (infix 1 '+ 2) '+ 3), то же самое что и (app '+ (app '+ 1 2) 3), при этом ассоциативность всё ещё играет роль. В тех же haskell/agda инфиксным операциям назначается ассоциативность (infixl / infixr).

quasimoto ★★★★
()
Ответ на: комментарий от anonymous

Мне прежде всего любопытно, можно ли без «ручного петушения списков» генерить преобразования чередующихся элементов в нечередующиеся и обратно: (a 1 b 2) <-> ((a 1) (b 2))

Это можно только если такая возможность заложена в возможности define-syntax-rule. Всё что там не предусмотрено нужно делать обычным схемовым кодом, обычными функциями.

quasimoto ★★★★
()
Ответ на: комментарий от anonymous

Интересно, подобный pattern matching можно перенести в common lisp или есть какие-то принципиальные ограничения?

Сами паттерны перенести - написать (defmacro define-syntax-rule (name ...) ... `(defmacro ,name ...)). Портировать всю макросистему из схемы (с гигиеной и её обходом) - точно не скажу.

quasimoto ★★★★
()
Ответ на: комментарий от anonymous

Можно правильный вариант?

Да, там опечатка. Надо так:

(define-syntax-rule (bad-let ((id expr) ...) body ...)
  (let ((id expr) ...) body ...))

Мне прежде всего любопытно, можно ли без «ручного петушения списков» генерить преобразования чередующихся элементов в нечередующиеся и обратно: (a 1 b 2) <-> ((a 1) (b 2))

первое выражение из второго можно сделать так: ((x ...) ...) -> (x ... ...)

второе из первого в обычной схеме нельзя. В Racket можно так: ((~seq id num) ...) -> ((id num) ...)

Интересно, подобный pattern matching можно перенести в common lisp или есть какие-то принципиальные ограничения?

Можно.

anonymous
()
Ответ на: комментарий от shty

для меня «руками» - это когда для каждого выражения ты сам должен составлять схему разбора, так вот в хаскеле - это не «руками»

Ну а для меня «руками» - это как раз то, что в хаскеле, в том числе.

anonymous
()
Ответ на: комментарий от shty

давай ещё раз - я её видел и я с этой оценкой несогласен, с математической т.з. - это очень слабая, неустойчивая, если хочешь, оценка

В чем же ее неустойчивость? Там был приведен пример элементарного преобразования, как оно выглядит в лиспе и как в хаскеле. Любое преобразование состоит из комбинации элементарных, если элементарные преобразования в 10 раз длиннее и запутаннее, то и все будут так же в 10 раз длиннее и запутаннее.

anonymous
()
Ответ на: комментарий от quasimoto

Например, в хаскеле макросов нет. Есть обычные функции которые которые ...

Ну так и в лиспе макросов нет. Там есть обычные функции, которые работают со списками или каким-то другим представлением АСТ.

Да, без фолдов и мапов нельзя. Я, например, не хотел бы, чтобы нельзя было строить AST конструкторами и комбинаторами.

Так никто не предлагает запретить строить АСТ конструкторами и комбинаторами. Речь о том, что было бы неплохо иметь и высокоуровневые средства.

Но в схеме тоже не получится без фолдов. Всё что выходит за рамки того что умеют паттерны генерируется обычным схемовым кодом.

Конечно. Но если мы генерируем выражения для ЯП с гомоиконным синтаксисом, то даже простейший pattern language покрывает 99% юзкейса.

Но совсем другое на уровне использования

Да одинаково все на уровне использования.

Мои две строчки берут цитированную бинарную функцию и цитированный список аргументов и расставляют скобочки (одна слева, другая справа). На самом деле тут вообще нет ничего интересного - это обычные foldl / foldr, работающие с типами (Q Exp), т.е. с цитированными AST.

Вот это кстати интересный такой вопрос. Если запихать в квазицитату (1 + 2 + 3) то будет сгенерирован АСТ для выражения ((1 + 2) + 3)? Вот и еще один плюс ЯП с гомоиконным синтаксисом - код сам по себе является АСТ, никаких трансформаций в уме производить не надо.

Изначально я сказал, что языку не нужно быть гомоиконным и не нужно отказываться от конкретного синтаксиса, чтобы иметь возможность мета-вычислений.

Ну, конечно, возможно, с этим никто и не спорил. Речь ведь о том, что эта возможность сродни эквивалентности тьюринг-полных ЯП. В теории они эквивалентны, а на практике - совсем нет.

Но ты сказал, что тогда эти вычисления будут «сложными». Очевидно, если в каждую задачу, через раз, совать мета-вычисления, то получится некрасиво. Но если пользоваться ими только по делу, то ничего.

Ну так в этом вся соль. Вот есть у нас инструмент - макросы, если этот инструмент прост и удобен в использовании (в гомоиконном ЯП) - то «по делу» - это чуть менее, чем везде. То есть инструмент юзабелен. Если же он кривой и неудобный (как в негомоиконном ЯП), то «по делу» - это чуть более, чем нигде. То есть инструмент неюзабелен. И в этом случае нам следует обосновывать каждое его применение.

Что такое чистое (1 + 2 + 3) если в языке нет инфикса?

А откуда мы знаем что есть в языке? Нам просто надо сгенерить вот такое вот выражение. чего там в языке - нас не волнует никак. Просто вот интересно, (1 op 2 op 3) в квазицитате в хаскеле какой АСТ построит, если op - это какой-то оператор, который передается в ф-ю и ассоциативность его заранее неизвестна и известна быть не может?

anonymous
()
Ответ на: комментарий от anonymous

Если запихать в квазицитату (1 + 2 + 3) то будет сгенерирован АСТ для выражения ((1 + 2) + 3)?

Да. Т.е. (infix (infix 1 + 2) + 3).

Просто вот интересно, (1 op 2 op 3) в квазицитате в хаскеле какой АСТ построит, если op - это какой-то оператор, который передается в ф-ю и ассоциативность его заранее неизвестна и известна быть не может?

Если написать [| 1 $op 2 |], то будет сгенерирован кривой AST - (app (app 1 op) 2). М-да :) Написать [| 1 `$op` 2 |] или [| 1 $`op` 2 |] не получится, остаётся только писать [| $op 1 2 |], [| $op 1 ($op 2 3) |] и т.п. Либо использовать свёртку (запись 1 op 2 op 3 обычно подразумевает, что мы знаем ассоциативность op и это суть fold* op [1, 2, 3]).

Вообще, выражение 1 op 2 op 3 даже в математике не имеет произвольного смысла - так обычно пишут, если op ассоциативна (теорема о семантической незначительности расстановки скобок выводится из самого свойства операции быть ассоциативной).

На тему возможных полезных изменений в TH есть такой материал - http://hackage.haskell.org/trac/ghc/blog/Template Haskell Proposal.

quasimoto ★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.