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/

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

будут справа скобки.

Так где они будут после построения АСТ (то есть до того, как мы узнали ассоциативность)?

Это не функции, это Quote / Splice в виде конструкторов AST.

Конструкторы - это функции. И, кстати, Quote/Eval, а не Quote/Splice.

В AST нет конструктора splice. Есть quote. splice это просто apply когда голова - символ макроса.

Ну он есть, просто вырожден. Так ведь и quote в данном случае вырожден, значит следует считать, что его нет.

ADT (~ AST у нас тут) и его поведение задаётся сигнатурами конструкторов, задаёт поведение и сигнатуры аккессоров. Это ключевые моменты.

AST задается его грамматикой, а в виде каких ADT оно будет представлено - это дело десятое, ведь всегда можно сделать враппер к другому эквивалентному представлению. Так что здесь следует говорить о классе представлений АДТ, который соответствует данной грамматике. Выбор конкретного представителя класса ничего не меняет - как и всегда при выборе одного объекта из совокупности изоморфных :)

Нет, eval замкнут.

Конечно замкнут, но тип у него Expression -> Datum, иначе это не евал, а какая-то профанация.

Datum, или Value, содержится в Expression.

Нет, наоборот - Expression содержится в Datum. То есть код - некоторый частный случай данных, не наоборот.

Вынести, т.е. агрегировать, values при наличии конструктора quote не получится (да это и просто неудобно / не нужно).

коненчо, не получится. Метацикличность нельзя формально выразить :)

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

Метацикличность нельзя формально выразить

Это безусловно очень важное преимущество Лиспа, ведь оно так повышает ЧСВ лиспокодера.

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

Так где они будут после построения АСТ (то есть до того, как мы узнали ассоциативность)?

Попробую так - если у нас функция отдаётся аргументом, то никакой ассоциативности у неё быть не может (поэтому те штуки в TH не работают), для неё будет простой AST с AppE. Писать [| a `f` b |] можно только для объявленных функций (возможно, указана ассоциативность), [| a ? b |] - для объявленных операторов (тоже).

Конструкторы - это функции. И, кстати, Quote/Eval, а не Quote/Splice.

Это особого рода функции (у них единственное правило rewriting - identity). Может, я вообще считаю за функции не identiчные rewriting rules. Нет не eval, почему? Eval как раз обычная функция, это _точно_ не конструктор (сам посуди). В лиспах нету аналога конструктора splice.

Так ведь и quote в данном случае вырожден

Откроем любой стандарт - спец. форма quote есть, самая обычная, ни во что не вырожденная.

но тип у него Expression -> Datum

Пусть так.

Нет, наоборот - Expression содержится в Datum

Они взаиморекурсивны - содержатся в друг друге (агрегируют друг друга).

data Val
  = Lit Lit
  | Lam [Exp] Exp
  | Quote Exp

data Exp
  = Var Var
  | Val Val
  | App Exp [Exp]
  | Splice Exp [Exp]
quasimoto ★★★★
()
Ответ на: комментарий от quasimoto

для неё будет простой AST с AppE. Писать [| a `f` b |] можно только для объявленных функций (возможно, указана ассоциативность), [| a ? b |] - для объявленных операторов (тоже).

Ну и какой конкретно будет АСТ в случае [| 1 `op` 2 `op` 3 |]?

Это особого рода функции

Функция особого рода - тоже функция.

Может, я вообще считаю за функции не identiчные rewriting rules.

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

Нет не eval, почему? Eval как раз обычная функция, это _точно_ не конструктор (сам посуди).

Ну да, не конструктор. А кто тебе сказал, что Quote - конструктор? Просто тип quote: Datum -> Expression, тип eval: Expression -> Datum. Между ними как бы двойственность. А splice = expand (Expression -> Expression). Ты просто с какого-то перепугу решил сделать их конструкторами, хотя они семантически конструкторами быть не могут...

Откроем любой стандарт - спец. форма quote есть, самая обычная, ни во что не вырожденная.

Ну и сплайс есть, в чем проблема, я не понял? Просто нету определенной формы, которая его делает, он внутри экспанда происходит.

Они взаиморекурсивны - содержатся в друг друге (агрегируют друг друга).

Проблема в том, что они содержат друг друга как обычные объединения (не размеченные), откуда следует val = expression, что и есть определение гомоиконности :)

То есть такой пример:

(define (f x) x) ; просто определили какую-то функцию, не важно какую
`(1 2 ,f)
Так вот `(1 2 ,f) задает определенный АСТ (кстати, в лиспе АСТ это именно консы, а не деревья, то есть АСТ может быть и зациклен сам на себя) и третий элемент этого АСТ - это именно _функция_. Не символ f, а именно функция, которую мы получаем при (eval 'f). Ну да, ты можешь сказать, что это все рантайм-значения, по-этому другой пример:
#lang racket
(begin-for-syntax
  (define (f x) x))

(define-syntax (macro stx)
  #`(list 1 2 #,f))
->
Добро пожаловать в DrRacket, версия 5.2.0.1--2011-11-01(98d8acf/a) [3m].
Язык: racket [выбранный].
> f
. . collects\racket\private\more-scheme.rkt:268:2: reference to an identifier before its definition: f
> (macro)
'(1 2 #<procedure:f>)
> 
то есть двойственность данные-код несколько глубже, чем ты себе представляешь и так как ты пытаешься ее через АТД описать нельзя.

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

Ну и какой конкретно будет АСТ

runQ [| 1 `op` 2 `op` 3 |]
-- >
InfixE (Just (InfixE (Just (LitE (IntegerL 1))) (VarE op) (Just (LitE (IntegerL 2))))) (VarE op) (Just (LitE (IntegerL 3)))

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

Буду иметь это в виду.

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

Так и что будет, если потом внезапно выяснится, что op был правоассоциативен?

f = (+)

t1 = runQ [| 1 `f` 2 `f` 3 |]
-- InfixE (Just (InfixE (Just (LitE (IntegerL 1))) (VarE Main.f) (Just (LitE (IntegerL 2))))) (VarE Main.f) (Just (LitE (IntegerL 3)))

infixr 7 `g`
g = (*)

t2 = runQ [| 1 `g` 2 `g` 3 |]
-- InfixE (Just (LitE (IntegerL 1))) (VarE Main.g) (Just (InfixE (Just (LitE (IntegerL 2))) (VarE Main.g) (Just (LitE (IntegerL 3)))))

t3 = runQ [| \a b c -> a * b + c |]
-- LamE [VarP a_0,VarP b_1,VarP c_2] (InfixE (Just (InfixE (Just (VarE a_0)) (VarE GHC.Num.*) (Just (VarE b_1)))) (VarE GHC.Num.+) (Just (VarE c_2)))

t4 = runQ [| \op -> 1 `op` 2 `op` 3 |]
-- LamE [VarP op_0] (InfixE (Just (InfixE (Just (LitE (IntegerL 1))) (VarE op_0) (Just (LitE (IntegerL 2))))) (VarE op_0) (Just (LitE (IntegerL 3))))

t5 op = runQ [| $op ($op 1 2) 3 |]
-- t5 [| (+) |]
-- AppE (AppE (VarE GHC.Num.+) (AppE (AppE (VarE GHC.Num.+) (LitE (IntegerL 1))) (LitE (IntegerL 2)))) (LitE (IntegerL 3))
quasimoto ★★★★
()
Ответ на: комментарий от anonymous

В первом приближении можно считать, что [| ... |] это как `( ... ), а [| ... $(...) ... |] - как `( ... ,( ... ) ... ).

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

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

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

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

Такого не может случится (такие свойства у самого haskell-98).

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