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

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

Обоснуй выделенность паттерна Compiler, сошлись на Турчина :)

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

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

Фигасе, понятный. Уж лучше так:

(defmacro bad-let (bad-bindings &body body)
  `(let  ,(loop 
	     for name in bad-bindings by #'cddr
	     for value in (cdr bad-bindings) by #'cddr
	     collect (list name value)) ,@body))

(macroexpand-1 '(bad-let (a 1 b 2) (+ 1 2 3)))

(LET ((A 1) (B 2)) (+ 1 2 3))
no-such-file ★★★★★
()
Ответ на: комментарий от quasimoto

Не работает же

Дык список не корректный. При таком синтаксисе нельзя объявить переменные без связывания со значением:

[code] (bad-let (a b) (+ a b)) [/code]

Как понимать? a=b или a, b без значений?

no-such-file ★★★★★
()
Ответ на: комментарий от no-such-file

Схемеры cannot into macros.

Нет, это про общелисперов.

Гигиена такая гигиена...

А кто-то уже придумал способ писать работающие макросы без гигиены?

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

Обоснуй выделенность паттерна Compiler, сошлись на Турчина :)

Зачем обосновывать какую-то выделенность и на кого-то там ссылаться?

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

А кто-то уже придумал способ писать работающие макросы без гигиены?

А кто-то уже привел ITT работающий макрос с гигиеной?

no-such-file ★★★★★
()
Ответ на: комментарий от no-such-file

В CL такие три формы:

(let ((a 1) b) (list a b))
(let ((a 1) (b)) (list a b))
(let ((a 1) (b nil)) (list a b))

это одно и то же.

(bad-let (a 1 b) (list a b))

должно раскрываться в одну из этих трёх форм.

(bad-let (a b) (+ a b))

должно раскрываться в

(let ((a b)) (+ a b))

Берём такую функцию:

(defun pairs (list)
  (if (< 2 (length list))
     `((,(car list) ,(cadr list)) ,@(pairs (cddr list)))
     `(,list)))

(pairs '(a 1 b 2))
((A 1) (B 2))

(pairs '(a 1 b))
((A 1) (B))

(ну или как угодно на вкус) и пишем:

(defmacro bad-let (bad-bindings &body body)
  `(let ,(pairs bad-bindings)
     ,@body))

(macroexpand-1 '(bad-let (a 1 b 2) (list a b)))
(LET ((A 1) (B 2))
  (LIST A B))

(macroexpand-1 '(bad-let (a 1 b) (list a b)))
(LET ((A 1) (B))
  (LIST A B))

(macroexpand-1 '(bad-let (a b) (+ a b)))
(LET ((A B))
  (+ A B))

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

quasimoto ★★★★
()
Ответ на: комментарий от no-such-file
(defun pairs (list)
  (labels
      ((%pairs (list)
         (if (< 2 (length list))
             `((,(car list) ,(cadr list)) ,@(%pairs (cddr list)))
             `(,list))))
    (unless (null list)
      (%pairs list))))

А ещё оно не в TCO форме, и некрасиво.

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
()
Ответ на: комментарий от quasimoto

должно раскрываться в одну из этих трёх форм

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

Задача разбиения списка на пары выделена, ничего не потерялось (вроде нечётного последнего элемента), весь код генерируется валидный

Да да. (Let (nil) ... валидно ага.

no-such-file ★★★★★
()
Ответ на: комментарий от no-such-file

А кто-то уже привел ITT работающий макрос с гигиеной?

пожалуйста: [code] (define (f x) x) (define-syntax-rule (yoba x) (f x)) [/code] Слабо повторить на CL?

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

Да да. (Let (nil) ... валидно ага.

тыц

бай зэ вэй

pairs :: [t] -> [[t]]
pairs [] = []
pairs (x:y:zs) = [x, y] : pairs zs
pairs (x:xs) = [x] : pairs xs
quasimoto ★★★★
()
Ответ на: комментарий от 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 ★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.