LINUX.ORG.RU

Лисперы, что я делаю не так? - II


2

3

Я понял что я делал не так — я просто не использовал лисп.

Вощем, может кому полезно будет, человек пишет как дошел до жизни такой http://www.defmacro.org/ Честно говоря это мой уже не первый подход к снаряду. До этого раза поташнивало, сейчас думаю зашел. Действительно лисп оказался прост как грабли.

Без матов осознание того на сколько оно кульно описать тяжко.

Есть вопросы:

1) Кто-нибудь есть кто пользует vim, при этом пишет на лиспе?

2) Ясен хобот емакс мощнее, но как то оно не то. Есть кто пересел? Как ощущения вообще?

3) Practical Common Lisp ослилил. Что есть еще для просветления?

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

на самом деле это примерно как «написать GC для C++»
Ну написать то можно, если постараться, да вот есть пара моментов, ггг.

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

если ты имел ввиду меня(анонимуса выше того коммента, на который ты отвечал), то нет

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

> ну вот ты написал свой макрос с использованием aif (не сказав мне про it), а-ля (define-syntax-rule (macro test body) (aif test (... body)...)), а я загнал его «внутрь» aifa: (aif test (macro it (bla-bla-bla... it))), я-ж буду «в святой уверенности», что оба моих it-а - это одно и то-же - твоя гигиена разберётся, что я хотел? :)

Ну я сам не совсем понял, чего ты хотел :) «оба моих it-а - это одно и то-же» - имеется ввиду, что они оба относятся к внешнему aif, то есть равны значению выражения test? Так и будет.

ты погодь, не так шибко - в CL на `,`,@ делается «вообще всё»

Ну все, что делается в CL на `,`,`@ на паттернах тоже делается - при чем проще.

У меня уже волосы дыбом встали...

Думаю, с паттернами на атрибутных грамматиках это будет сделать элементарно. А вот на `,`,`,@... :)

«заранее подготовленные переменные» - это такая тривиальщина, что за написание из-за неё макр archimag оторвёт все конечности и то, что он за них примет...

Ты не понял. Имеется ввиду, что не делать бекквоты, то есть вместо #`(form x y #,@(fun z) y) например следует писать (with-syntax ([(patt...) (fun z)]) #`(form x patt ... y)).

не-не-не, если мне надо будет паттерном описывать итоговое выражение (все их варианты!), вместо пачки rest map filter `@,@@,, etc - никакой памяти не хватит...

Всмысле? Паттернами-то можно сразу варианты описывать, а с filter etc. придется делать тот же диспатч по паттернам - только руками, с ифами и кондами.

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

> Ну написать то можно, если постараться, да вот есть пара моментов, ггг.

[code] (define-syntax (macro stx) (syntax-local-introduce (syntax-case (syntax-local-introduce stx) [...]))) [/code] Все символы выведены из-под гигиены, никаких «моментов» нет.

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

>ты мне мой код показываешь? ну нормально, ок.

Тебя нет. Есть только вездесущий и многоликий анонимус.

anonymous
()
Ответ на: комментарий от anonymous
(define-syntax (macro stx)
  (syntax-local-introduce
   (syntax-case (syntax-local-introduce stx)
     [...])))
anonymous
()
Ответ на: комментарий от anonymous

> Есть только вездесущий и многоликий анонимус.

И священная копипаста.

anonymous
()

в тред элегантно входит С++0x и оставляет местных лисперо-схемеров без работы.

[](int x, int y) -> int { int z = x + y; return z; }

красота!

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

> в тред элегантно входит С++0x

И тут же уползает назад, униженный и оскорбленный тем, что для него нет и никогда не будет полноценного REPL.

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

> нет и никогда не будет полноценного REPL.

«Humanity^WREPL is overrated» почти (с)

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

> И тут же уползает назад, униженный и оскорбленный тем, что для него нет и никогда не будет полноценного REPL.

написать его то можно, интерпретаторы для С/С++ делали, вот только не сдались они никому и даром, разве что нескольким людям, ради которых нет смысла напрягаться

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

> интерпретаторы для С/С++

REPL это не интепретатор! В том же SBCL по умолчанию всё введённое в REPL компилируется в машинный код .

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

> вот только не сдались они никому и даром

Право, всё же не стоит употреблять подобную аргументацию. Ведь в зависимости от языка может кому-то оказаться не нужным отладчик, другим профайлер, третьим быстродействие. Что бы получить полноценный REPL язык должен проектироваться соответствующим образом. Сейчас я знаю о существовании двух таких языков - CL (плюс некоторые другие диалекты лисп) и Smalltalk.

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

>Сейчас я знаю о существовании двух таких языков - CL (плюс некоторые другие диалекты лисп) и Smalltalk.

а как же haskell(ghci)?

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

> Право, всё же не стоит употреблять подобную аргументацию

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

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

> Что бы получить полноценный REPL

Кстати, чем полноценный REPL отличается от неполноценного? За неполноценный предлагаю взять беспонтовый bpython, ну или что-нибудь по твоему выбору, только не сильно экзотичное.

язык должен проектироваться соответствующим образом.

Проектировать язык для REPL - это круто %)

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

> Кстати, чем полноценный REPL отличается от неполноценного?

Возможность интерактивной разработки, же. У них другой священной коровы то и нет.

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

>> Кстати, чем полноценный REPL отличается от неполноценного?

Возможность интерактивной разработки, же.

Да ну... я интерактивно разрабатываю скрипты в bash prompt. Является ли bash prompt примером «полноценной REPL»?

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

Ну сделай себе одну с диспатчем в рантайме - кто мешает?

А есть причина по которой нельзя сделать с диспатчем в компайлтайме?

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

> Является ли bash prompt примером «полноценной REPL»?

Символы можно переопределять на лету, во время выполнения команды. Хм, очень похоже.

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

замыкаться должен как раз заквоченный символ.

Т.е. макросистема схемы отличается от своего аналога в CL тем, что имеет кодволкер, который вот такой заквоченый список обрабатывает (в CL-то просто возвращается то что построили) и замыкает в том числе заквоченные переменные, т.е. работает с выражениями не как со списками, а как с AST. И что если на момент определения макроса x не определён, что тогда замыкать? В CL какой-то кусок кода из макроса может приобрести смысл только когда будет подставлен в то место в котором макрос был использован, в место с неким окружающий подставляемый код кодом. И как можно иметь фиксированный AST в языке в котором можно задавать счётное количество макросов (фактически, новых специальных форм). Например, у нас есть спец. форма if (часть AST) мы определим какой-нибудь iff - как он станет частью AST?

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

а как же haskell(ghci)?

http://hackage.haskell.org/trac/ghc/ticket/4929

Чтобы REPL был REPL-ом нужно чтобы ему можно было отдать *любой* замкнутый кусок кода. В GHCi даже к функциям нужно let подставлять, не говоря уж от типах/классах.

quasimoto ★★★★
()

Some deep philosophical differences exist between ANSI Common Lisp and Scheme, and they appeal to different programmer personalities. Once you learn more about Lisp languages, you can decide which dialect you prefer.

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

>В GHCi даже к функциям нужно let подставлять, не говоря уж от типах/классах.

Ну, GHCI вполне можно скоримть конкретный файл командой load. Только все-равно это не будет полноценным REPLом, поскольку компиляция будет только в байткод.

Но не нужно забывать что динамический CL использует свои типы большей частью как хинты для генерации эффективного кода, когда хаскель достаточно много считает при выводе типов. Это очень хорошо заметно при использовании любой комбинаторной библиотеки, того же Parsec'а, например.

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

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

На примере

Собственно, вот:

(defpackage #:foo
  (:use     #:common-lisp
            #:donuts.abs
            #:sb-walker)) ;; see $SBCL/src/pcl/walk.lisp

(in-package #:foo)

(defmacro define (form &rest value)
  (case-match form
    ((cons name args) `(defun ,name ,args ,@value))
    (symbol           `(defparameter ,form ,@value))))

(defmacro define-syntax-rule ((name &rest args) rule)
  `(defmacro ,name ,args
     ,(walk-form
       `,rule
       nil
       (lambda (form context env)
        (declare (ignore context env))
        (if (symbolp form)
            (if (boundp form)
                (symbol-value form)
                (error "Symbol ~A is unbound." form))
            form)))))

И потом:

(define x 5)
(define-syntax-rule (macro) (print x))
(let ((x 10)) (macro))
;=> 5

(define-syntax-rule (macro2) (print y))
; => The variable Y is unbound.

Так это должно быть?

А вообще - я опять говорю, что семантика схемы отображается в семантику CL без особых проблем. Кто-то когда-то в 90-ые годы релизовал R5RS на CL, причём не то чтобы это был какой-то интерпретатор - наоборот довольно прозрачная трансляция с помощью макросов (причем очень много равнозначных сущностей с одинаковыми или разными названиями). Дальше видим, что hygienic macros were an optional part of the Scheme standard in revision 4 and became mandatory in revision 5 (i.e. R5RS) и Kent Dybvig and Oscar Waddell have written a highly portable implementation of R5RS macros that only requires very few hooks into a Scheme implementation in order to work. It can be found at http://www.cs.indiana.edu/chezscheme/syntax-case/. Учитывая первое (об отображении R5RS схемы в CL) - о чём мы тогда говорим?

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

> Т.е. макросистема схемы отличается от своего аналога в CL тем, что имеет кодволкер, который вот такой заквоченый список обрабатывает (в CL-то просто возвращается то что построили) и замыкает в том числе заквоченные переменные, т.е. работает с выражениями не как со списками, а как с AST. И что если на момент определения макроса x не определён, что тогда замыкать?

Короче так, когда работает экспандер, то он раскрывает выражения в рамках некоторого локального контекста. Если экспандер наткнулся на какой-нибудь define/let, то определяемые там переменные кладутся в контекст. Далее, когда экспандер раскрывает тело/любую другую форму, то смотрит на символ и ищет в контексте ближайший символ с тем же именем и набором syntax marks, когда находит - связывает с ним (можешь открыть степер - там эти связи стрелочками показаны). Информация о том, с каким биндингом связан символ кладется в сам символ. Сперва связывание происходит при раскрытие самого тела макроса (то есть идентификаторы в макросе замыкаются на контекст области определения макроса). Потом когда мы макрос используем в коде, макрос раскрывается и экспандер опять устанавливает биндинги для тех же символов - то есть ищет по локальному контексту. В классическом случае символов с вопадающими марками в контексте не будет - по-этому остается только биндинг установленный при определении макроса, он и используется. Но если окажется что в контексте такой символ есть - будет использован он. Если мы уберем в макросе с символа марку (снимем гигиену то есть), то тогда всегда будет введен биндинг из контекста области вызова (т.к. без марки символ просто по имени будет сравниваться).

Например, у нас есть спец. форма if (часть AST) мы определим какой-нибудь iff - как он станет частью AST?

этот iff раксроется в последовательность базовых форм, которые сами по себе или в любой комбинации являются частью АСТ :)

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

> Так это должно быть?

то, что можно костылик сделать для топ-левела никто и не спорил. А вот если у нас последовательность вложенных контекстов, или макросы раскрываются в макросы тут и начинается самое интересное. кроме того - замыкаться на внутренний контекст это только дефолтное поведение, суть-то в том, что ты это поведение можешь контролировать. И еще: [code] (define x 5) (define-syntax-rule (macro) (display x)) (let ([x 10]) (define-syntax-rule (macro2) (display x)) (macro) (macro2)) [/code] что у тебя будет?

R5RS

2011 год сейчас, але. В r5rs нету syntax-case.

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

этот iff раксроется в последовательность базовых форм

Я просто подумал - какой там BNF? Если вроде такого:

if-expr  ::= if expr expr expr
lam-expr ::= lambda [var] [expr]
...
app-expr ::= apply expr [expr]
mac-expr ::= macro name [expr]

то можно было бы делать такой syntax-case:

(syntax-case expr
  ...
  ([macro 'iff ...] ...))

т.е. на любой пользовательский макрос как часть AST.

что у тебя будет?

Ничего, потому что (let ... (defmacro foo ...) (foo ...)) не хочет работать ни так ни с locally, ни ещё как-то - на момент раскрытия макрос foo не определён, поэтому экспандер думает, что foo это функция - а такой нет. И вообще, defmacro - toplevel форма only (как и все прочие toplevel формы).

2011 год сейчас, але. В r5rs нету syntax-case.

Ничего не знаю, я community.schemewiki.org цитировал - мол, достаточно R5RS чтобы надстроить, портабельно, всю эту макросистему.

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

> Я просто подумал - какой там BNF?

Такой, за исключением того, что макросов в bnf нет. То есть нету в bnf такой штуки как «форма вызова макроса».

то можно было бы делать такой syntax-case:

Гм, ну он так и делается. то есть

(syntax-case stx [(_ ...) ...] ...)

работает эквивалентно твоему:

(syntax-case expr ... ([macro 'iff ...] ...))

там прочерк идет, потому что в передаваемом макросу синтаксическом объекте первый элемент всегда будет сам этот макрос и этот объект всегда будет формой вызова макроса. По-этому нет смысла писать ,acro и указывать имя.

И вообще, defmacro - toplevel форма only (как и все прочие toplevel формы).

Ах, ок. Заменить дефмакро на макролет (на самом деле все дефайны внутри локального контекста заменяются именно на соответствующие let-формы, в частности, define-syntax-rule -> let-syntax).

Ничего не знаю, я community.schemewiki.org цитировал - мол, достаточно R5RS чтобы надстроить, портабельно, всю эту макросистему.

Что значит «портабельно надстроить эту макросистему»? Выразить syntax-case через syntax-rules в принципе невозможно. С другой стороны - на любом тьюринг-полном ЯП и далее по тексту.

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

Что значит «портабельно надстроить эту макросистему»?

Я про вот это - http://www.cs.indiana.edu/chezscheme/syntax-case/.

Выразить syntax-case через syntax-rules в принципе невозможно.

Там у них бустрап - можно видеть (define-syntax syntax-rules ...), (global-extend 'core 'syntax-case ...), (global-extend 'define-syntax 'define-syntax ...) и (define global-extend ...).

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

Ну так там с нуля написана реализация r6rs, это можно сделать хоть на брейнфаке. Вообще же, чтобы сделать syntax-case, надо как минимум полностью переписать экспандер. Так что гигиеническая семантика не может быть выражена в негигиенической никак. Я под «надстройкой» понимаю просто набор макросов, которые будут раскрываться в уже существующие формы. Без переписывания рантайма.

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

> рантайма.

Рантайм - всмысле read-eval-print и соответствующие функции.

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

> Так что гигиеническая семантика не может быть выражена в негигиенической никак.

а вот наоборот - 10 строк.

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

Так что гигиеническая семантика не может быть выражена в негигиенической никак.

Всё что нужно это некая функция walk которая обходит body и обеспечивает, что макрос ссылочно-прозрачный и использует скоп места определения, а не места раскрытия. Это и есть наиболее общее определение гигиены.

Вот в примере выше - можно смотреть на такой макрос = (defmacro new-defmacro (name args &body body) `(defmacro ,name ,args ,@(walk-form body ...тут мы чекаем переменные...))) как на гигиенический CL-макрос, там всё правильно с этой точки зрения. Только это конечно не такие макросы как в scheme, не такие во всём что расходится с общим определением гигиены. И syntax-case нету, и мало ли чего там ещё нету :). Но гигиена вроде не проблема.

Остаётся вопрос про «тыщи строк кода» которые должны быть реализацией этой функции walk - ну так в схеме те же тыщи строк кода, но не отдельно от макросистемы, а прямо в ней. И тут мы возвращаемся к «отогональности» инструментов в языке.

Без переписывания рантайма.

Разве по тем ссылкам переписывают уже имеющийся рантайм? По моему там нет ни eval, ни всего остального из R5RS. Тот проект как раз и предназначен, чтобы можно было имея минимальную схему загрузить этот pp файл (исправить глюки) и прибавить таким образом к рантайму syntax-case и syntax-rules.

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

> Хм, так как у нас обстоит дело с определением произвольного кодеволкера?

Что такое «произвольный кодеволкер»?

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

> Что такое «произвольный кодеволкер»?

Хм, это «code walker», который может производить произвольную обработку переданных данных.

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

> Всё что нужно это некая функция walk которая обходит body и обеспечивает, что макрос ссылочно-прозрачный и использует скоп места определения, а не места раскрытия. Это и есть наиболее общее определение гигиены.

Надо будет сперва раскрыть body. А сделать это нельзя - его можно раскрыть только после того, как макрос будет вызван в самом коде. То есть да, все дело в ф-и walk, вот только вызывать эту ф-ю надо в самом экспандере. Просто подставив это дело в макрос такое сделать никак не получится.

Остаётся вопрос про «тыщи строк кода» которые должны быть реализацией этой функции walk - ну так в схеме те же тыщи строк кода, но не отдельно от макросистемы, а прямо в ней.

Ну да, на любом тьюринг-полном языке можно реализовать интерпретатор схемы. Я никогда с этим не спорил. Вопрос в том, можно ли именно сделать «надстройку» - то есть выразить гигиену в рамках уже имеющегося языка. В CL - нельзя.

Разве по тем ссылкам переписывают уже имеющийся рантайм? По моему там нет ни eval, ни всего остального из R5RS.

expand там переписывается.

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

> Хм, это «code walker», который может производить произвольную обработку переданных данных.

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

anonymous
()

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

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

Вообще, самый полезный источник знаний о лиспе — исходники самого лиспа. Я смотрел SBCL. Там, в частности, можно узнать как на основе трех граблей строится система, которая вполне себе неплохо работает. Впечатлило. По аналогии соорудил игрушечный выплевыватель .NET кода, который, о чудо, тоже работает. Меня порадовало как это оказалось легко и просто.

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

>На выходных похлебывая чаек поигрался с лиспом.

уверен, что с лиспом игрался? в твоем возрасте играются с несколько другими вещами

Мне понравилось о чем я и сообщил тут

ты - никто, твое мнение никому не интересно и «ненужно»

исходники самого лиспа.

ты уверен, что у тебя есть исходники «самого лиспа»?

основе трех граблей строится система

ты про китов? это - не лисп, это - индия!

Впечатлило.

опять. ты - никто.

Меня порадовало как это оказалось легко и просто.

написать хелловорд?

Меня порадовало как это оказалось легко и просто.

ну так и в дамскую комнату ходить легко и просто.

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

> ну так и в дамскую комнату ходить легко и просто.

О, мадам, вам виднее.

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