LINUX.ORG.RU

Ищу соавтора! Реализация Lisp.

 


5

8

Я занимаюсь разработкой нового диалекта Lisp, параллельно в вузе читаю спецкурс по семантике языков программирования. По ссылке можно прочитать о некоторых моих идеях:

https://drive.google.com/file/d/0B13ti3tFkQZlSkFPV3NuMHR4eGc/view?usp=sharing

Пока исходников нет в общем доступе, т.к. я активно работаю над ними и мне тяжело будет поддерживать к ним доступ в инете. Ищу соавтора для допиливания реализации и/или написания книги по семантике Лиспа. Желательно из Санкт-Петербурга. Обращайтесь вконтакте: http://vk.com/maliculo

Еще хочу прорекламировать свою публичную лекцию в cs club по Лиспу: http://compsciclub.ru/node/2767

Ответ на: комментарий от quantum-troll

он не может в нормальную систему типов

точно. готов выслушать твои предложения.

синтаксис можно сделать почеловечнее

ну посмотри на K, там нормальный.

добавить штук из функциональных языков

каких? мне обычно наоборот, в «функциональных языках» не хватает «штук» из apl/j/k.

использовать юникод в коде

сама по себе идея хорошая, вот, скажем, Dyalog APL вполне себе юникодный. как сделать это так, чтобы оно понятным образом взаимодействовало со стандартным набором операций в языке (который может не совпадать с apl characters), и чтобы всякие юникодные приколы типа combining characters ниоткуда не торчали, ещё не придумано.

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

И в чем проблема? Все прекрасно работает.

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

Чтобы объяснить проблему, нужно немного терминологии. Различают интроспекцию (способность программы получать информацию о своей структуре или состоянии) и интерцессию (способность программы изменять свою структуру или состояние). Соответственно бывает структурная интерцессия и структурная интроспекция, поведенческая интерцессия и поведенческая интроспекция. Макросы основываясь на структуре программы изменяют ее поведение, соответственно, они соединяют структурную интроспекцию с поведенческой интерцессией. Логичнее соединять структурную интроспекцию с структурной интерцессией и поведенческую интроспекцию с поведенческой интерцессией.

Я не против того, чтобы ты оставался в каменном веке, поэтому дальнейшая дискуссия с тобой не будет вестись пока ты не прочитаешь про fexpr'ы и работы John Shutt.

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

точно. готов выслушать твои предложения

Ну хотя бы что-нибудь на замену коробкам и ООП из 90-х, торчащего сбоку костылём. И чтобы функции могли быть полноценным типом (в k это таки сделано, влияние лиспа сказывается). Ну и полноценную систему модулей, хотя это уже не типы. А вот в какой-то Julia уже параметрический полиморфизм есть, все дела...

ну посмотри на K, там нормальный.

У J он во многих местах всё-таки лучше, но в то же время много сомнительных вещей вроде !:. Что мне действительно нравится и не нравится в J, так это неявное программирование. Это действительно выразительная вещь, позволяющая сделать многие вещи короче и яснее, но принуждение к её использованию приводит к тому, что то, что могло бы выглядеть как

pi =: fmt <.@{1p1 * 10^y.} y.
PiList =: pi <: *: y.
имеет такой вид:
pi =: [: ": [: <.@o. 10"_^]
PiList =: [: pi [: <: [: *: ]

каких? мне обычно наоборот, в «функциональных языках» не хватает «штук» из apl/j/k.

Первое, что приходит в голову: let-in, where, сопоставление с образцом. Казалось бы, мелочь, но позволяет сделать код не только короче, но и читаемее.

А ведь ещё можно подумать о переписывании термов, как в Pure...

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

и как у такой модели с безопасностью?

Принципиальный момент - программы в такой модели не имеют доступа к оборудованию иначе как через интерпретатор. Разделим безопасность на две категории - однопользовательскую и многопользовательскую. Проблемы с безопасностью однопользовательской системы возникают тогда, когда программист изменяет какие-то данные, от которых зависит функционирование системы. Раз почти все примитивы находятся в библиотеке, программист легко может переопределить if или quote и тем самым сломать функционирование всей системы. Для предотвращения подобных проблем обычно в языках программирования используют константы и немутабельные объекты. Но это не путь Лиспа. Common Lisp, например, при попытке переопределения встроенных функций входит в break-loop в котором можно таки заставить его переопределить константу. Таким образом, после старта системы и прогона стандартной библиотеки все примитивы помечаются как системные, доступные для осознанного изменения.

Вторая проблема - многопользовательские системы. Я не специалист в этом, но я знаю хорошее решение из мира языков программирования - песочницы. Для этого надо сделать окружения (отображения символов на переменные) объектами первого класса, как в MIT Scheme или T. При входе в систему нового пользователя он получает пустое окружение, которое унаследовано от системного. Системным окружением владеет root, поэтому хотя новый пользователь будет иметь доступ к примитивам системы, он не будет иметь прав их изменять. Точно как же новый пользователь получает не системный интерпретатор, а лишь его копию, поэтому если он захочет изменить интерпретатор (функция eval, кстати, тоже может быть generic, т.е. мутабельной), то это никак не отразится на работе других агентов системы. Все пользователи изолированы, т.к. работают в разных окружениях, но могут взаимодействовать друг с другом помещая объекты в публичные окружения.

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

Пиши мне в личку, все обсудим.

Заманчивое предложение от анонима.

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

Да, я уже писал, что макросы - функции из AST в AST, поэтому они тоже объекты первого класса.

Ну так в чем проблема, ты можешь сформулировать?

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

А в каком? Еще раз - ты можешь сформулировать в каком смысле макросы не являются объектом первого класса? Макрос, по определению, это просто ф-я, которую можно вызвать в компайлтайме для трансформации АСТ. То есть макрос - это объект с которым можно делать АБСОЛЮТНО ВСЕ что можно делать с ф-ями + еще кое-что. В этом смысле тогда объектами первого порядка не являются обычные ф-и - потому что их нельзя использовать там, где можно использовать макросы.

Макросы основываясь на структуре программы изменяют ее поведение

Нет, не изменяют. Макросы генерируют программу. До того как отработали макросы - у тебя и нету никакой программы.

Я не против того, чтобы ты оставался в каменном веке, поэтому дальнейшая дискуссия с тобой не будет вестись пока ты не прочитаешь про fexpr'ы и работы John Shutt.

Фекспры - это просто функции, язык с фекспрами и язык без фекспров - одинаковые языки. Ну, если ты разбираешься в теме, то сам это прекрасно понимаешь.

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

Ну так в чем проблема, ты можешь сформулировать?

Специальные формы (специальные операторы в терминологии CL) в Scheme или CL являются объектами первого класса по твоему?

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

Специальные формы (специальные операторы в терминологии CL) в Scheme или CL являются объектами первого класса по твоему?

Спецформы - это не макросы.

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

Спецформы - это не макросы.

Я знаю. Макросы - способ эмуляции Лиспом возможности создания новых специальных форм. Специальные формы определяемые программистом не должны отличаться от системных. Макросы - функции, специальные формы - нет. Вот где противоречие.

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

Макросы - функции, специальные формы - нет. Вот где противоречие.

Спецформы нигде не могут быть функциями.

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

Спецформы нигде не могут быть функциями.

Все верно, в CL и Scheme не могут. В 3-Lips могут, они называются реификаторами (reifier). Как выглядит реализация в интерпретаторе специального оператора? Например, так (в cps):

(defun eval-quote (args env cont)
    (funcall cont (car args)))

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

Pascal Costanza «Reflection for the Masses».

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

define, lambda, quote либо определяются интерпретатором на основе встроенных функций, либо нужно делать трюки, чтобы определить их на основе пользовательских функций, т.к. тут возникает проблема курицы и яйца. Проще всего пояснить идею на примере if. Есть встроенная функция ef, которая ведет себя как оператор if, но вычисляет все свои аргументы. Еще есть функция proc-to-special которая конвертирует функцию в специальный оператор. Итак, определение if из стандартной библиотеки:

(define if
     (proc-to-special (lambda (args env cont)
            (eval (first args)
                  env
                  (lambda (first-evaled)
                          (eval (ef first-evaled
                                     (second args)
                                     (third args))
                                env
                                cont))))))

Как можно видеть реификатор получает полное состояние вычислительного процесса (это называется реификация), которое было до его запуска. Он преобразует это состояние и реинсталирует его обратно в интерпретатор передавая в eval. У интерпретатора есть свой формат континуаций, поэтому он должен конвертировать пользовательскую функцию представляющую континуацию в свой формат (это называется отражение). Как видно интерпретатор построен на двух процессах - реификации (передачи состояния из интерпретатора в программу) и отражения (передачи состояния обратно из программы в интерпретатор).

lambda определяется на основе функции make-closure от 3 аргументов - lambda-list, тело, окружение. Но это определение не вынести в библиотеку, т.к. для библиотечного определения lambda нужен lambda. Тем не менее его исходный код доступен в рантайме.

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

Чтобы вычислить реификатор нужно конвертировать его обратно в функцию, конвертировать текущее продолжение в функцию и вызвать apply от этой функции передав cdr вычисляемой формы, окружение, и континуацию.

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

funcall нужен только в lisp-2. Мне больше нравится lisp-1.

Он и в lisp-1 есть. (f x) - вот это и есть функолл. Тот факт, что он не присутствует _явно_, не значит, что его нет вообще, аппликация - такая же синтаксическая форма, как лямбда.

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

define, lambda, quote либо определяются интерпретатором на основе встроенных функций, либо нужно делать трюки, чтобы определить их на основе пользовательских функций

Ну если так - то в схемке спецформы это тоже обычные функции, объекты первого порядка.

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

Ну так реализацию спецформы apply можно увидеть?

Так это часть интерпретатора. Не вижу смысла сбрасывать сюда код интерпретатора на CL, а метациклический я пока не написал (хотя это довольно тривиально, но руки не дошли). Есть метациклический интерпретатор 3-Lisp, но там синтаксис и семантика форм немного другая. Вот он (normalize - аналог eval, reduce - аналог apply):

(define NORMALISE
  (lambda simple [exp env cont]
    (cond [(normal exp) (cont exp)]
          [(atom exp) (cont (binding exp env))]
          [(rail exp) (normalise-rail exp env cont)]
          [(pair exp) (reduce (car exp) (cdr exp) env cont)])))

(define REDUCE
  (lambda simple [proc args env cont]
    (normalise proc env
      (lambda simple [proc!]                          ; PROC continuation
        (if (reflective proc!)
            (↓(de-reflect proc!) args env cont)
            (normalise args env
                       (lambda simple [args!]         ; ARGS continuation
                         (if (primitive proc!)
                             (cont ↑(↓proc! . ↓args!))
                             (normalise (body proc!)
                                        (bind (pattern proc!) args! (environment-of proc!))
                                        cont)))))))))

В строке, которая вычисляет реификатор вызывается функция de-reflect, которая преобразует реификатор обратно в функцию. Идея следующая: вычисляем car формы, а затем в зависимости от его типа производим или нет вычисления списка cdr.

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

Ну если так - то в схемке спецформы это тоже обычные функции, объекты первого порядка.

В Scheme спец операторы - функции в языке, на котором она реализована. Из Scheme получить к ним доступ нельзя.

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

В Scheme спец операторы - функции в языке, на котором она реализована. Из Scheme получить к ним доступ нельзя.

Это, в общем, чисто формальное ограничение. Я же могу сделать так:

(define-syntax-rule (my-begin e ...)
  (begin e ...))
теперь my-begin работает точно так же как спецформа, но является макросом. Заменив подобным образом все спецформы (что тривиально) я получаю язык, в котором нету спецформ.

В Scheme спец операторы - функции в языке, на котором она реализована.

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

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

но эта реализация reduce уже использует реализованный редьюс, например: "(normalise args env ..." чтобы прменить normalise к аргументам, надо, чтобы редьюс УЖЕ БЫЛ.

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

но эта реализация reduce уже использует реализованный редьюс, например: "(normalise args env ..." чтобы прменить normalise к аргументам, надо, чтобы редьюс УЖЕ БЫЛ.

Конечно, никак иначе нельзя. Иначе будет бесконечная регрессия. Та же самая проблема есть в CLOS. CLOS определен на самом себе, но там рекурсия тоже терминируется.

Я думаю, эту дискуссию можно закончить, т.к. все аргументы высказаны. Все сводится к различию в нашем понимании идеи объектов первого класса. Мне видится, что твое понимание связанно с формальным следованием определения идеи «первого класса», я же выдвигаю аргументы философского толка. Я надеюсь, читатели смогут получить пользу от этого обсуждения. Думаю, многие читатели впервые слышат про рефлективные процедуры и 3-Lisp. Надеюсь также, что найдется человек, который бы мне помог доделать сложную работу. У меня не так много времени чтобы ее завершить, т.к. продолжительность моей жизни ограничена тяжелой болезнью.

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

Он и в lisp-1 есть. (f x) - вот это и есть функолл. Тот факт, что он не присутствует _явно_, не значит, что его нет вообще, аппликация - такая же синтаксическая форма, как лямбда.

Вот это глубокая мысль. До этого я думал, что либо ты вообще ничего не понимаешь, либо толлингом занимаешься. Кстати, забавно, что присутствие серьезной дискуссии отпугнуло людей, любящих лиспосрачи. Всего тебе хорошего! Но не останавливайся на Scheme. Человечество так много всего уже напридумывало.

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

Все сводится к различию в нашем понимании идеи объектов первого класса.

Для вещей, имеющий вполне четкое и конкретное определение никаких различий в понимании быть не может.

я же выдвигаю аргументы философского толка

Ты вообще пока никаких аргументов не выдвинул. Есть вполне четкое определение объекта первого класса - это объект, которым ничем «не выделяется» относительно других, то тот, с которым мы можем делать то же самое, что и со всеми остальными объектами. С макросами - можем.

Мне видится, что твое понимание связанно с формальным следованием

Нет, оно связано с практикой. У нас есть ф-и, ф-и, очевидно, в лиспе объекты первого порядка. Макросы ничем не отличаются от ф-й, значит, тоже являются объектами первого порядка. Если макросы не являются объектами первого порядка - то значит они либо чем-то отличаются, либо ф-и тоже таковыми не являются.

Думаю, многие читатели впервые слышат про рефлективные процедуры и 3-Lisp. Надеюсь также, что найдется человек, который бы мне помог доделать сложную работу.

Я напоминают, что идея фекспров выброшена на помойку не один десяток лет назад. Твоя «сложная работа» давным-давно доделана и было признано, что никаокго толку от этой работы нет.

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

Всего тебе хорошего! Но не останавливайся на Scheme. Человечество так много всего уже напридумывало.

Дык схемку придумали уже после того как выкинули фекспры нахер.

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

Я напоминают, что идея фекспров выброшена на помойку не один десяток лет назад. Твоя «сложная работа» давным-давно доделана и было признано, что никаокго толку от этой работы нет.

А историю после статьи Kent Pitman «Special Forms in Lisp» ты знаешь? Мне уже надоело...

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

А историю после статьи Kent Pitman «Special Forms in Lisp» ты знаешь?

С тех пор как фекспры выбросили на помойку, ничего нового в этой области не придумали. Фекспры остались точно теми же самыми фекспрами. Если кому-то захотелось обмазаться окаменевшими какахами и написать соответствующий диссер - проблема этих людей.

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