Здравствуйте, yumi, Вы писали: Y>Здесь.
Кстати, а нужен ли в итоге лиспосинтаксис? Я вот не очень знаком с nemerle и boo, но там есть макросы и без него.
Здравствуйте, Mr.Cat, Вы писали:
MC>Здравствуйте, yumi, Вы писали: Y>>Здесь. MC>Кстати, а нужен ли в итоге лиспосинтаксис? Я вот не очень знаком с nemerle и boo, но там есть макросы и без него.
Безусловно.
Чтобы иметь удобную возможность оперировать с кодом из lisp, опять же lisp-синтаксис (лично мне) кажется очень стройным и логичным.
S-выражения достаточны для описанной задачи, а так же универсальны и однотипны.
+ Очень легка реализация такого вот DSL на generic-ах + destructuring-bind, типа такой:
;; описываем как парсить объявления типов
(defgeneric parse-type-decl (context type-id args))
;; объявления структур
(defmethod parse-type-decl (context (type-id (eql :struct)) args)
(destructuring-bind (name members) args
;; further impl...
))
;; typedef объявления
(defmethod parse-type-decl (context (type-id (eql :typedef)) args)
(destructuring-bind (source-name aliased-name) args
;; further impl...
))
;; и т.д.
в точке разбора выражений типа вызываем parse-type-decl "и имеем уважение"(с)
Здравствуйте, Mr.Cat, Вы писали:
MC>Кстати, а нужен ли в итоге лиспосинтаксис? Я вот не очень знаком с nemerle и boo, но там есть макросы и без него.
Нужен или нет, каждый сам для себя решает
Лиспосинтаксис aka s-expressions проще, в том смысле, что ими проще манипулировать, трансформировать, ведь это и есть по сути AST. В немерле уже сложнее, в основном видимо из-за наличия синтаксиса, многостадийности компиляции и нескольких AST на разных стадиях компиляции. Например, точно не помню, очень примерно, на этапе лексического анализа используется PreParse tree, далее, ParseTree, потом TypedTree, как-то так. Т.е. внутри макроса, мы должны знать, на каком этапе мы и какое дерево нам доступно.
Здравствуйте, yumi, Вы писали:
Y>... Y>ЗЫ: документации жаль никакой нет
Это да.
Если серьезно — в прошлом году меня посещали схожие мысли, что и автора "Amplifying C".
В первую голову смотрел на cl-dsl, но он мне не очень понравился своей навороченностью, отсутствием документации и проработанным наборов юнит тестов.
В свободное время пытаюсь сделать нечто подобное, в чем то упростив, в чем то усложнив концепцию обработки DSL-кода.
Благо — это хороший способ изучить лисп вообще
Да и черновые прототипы подобных вещей делаются за буквально за несколько минут на clisp, в отличие от других ЯП.
Здравствуйте, A13x, Вы писали: A>Чтобы иметь удобную возможность оперировать с кодом из lisp, опять же lisp-синтаксис (лично мне) кажется очень стройным и логичным. A>S-выражения достаточны для описанной задачи, а так же универсальны и однотипны.
Я тоже люблю s-выражения, но подозрительно отношусь к тому, чтобы насаждать s-выражения там, где их изначально не было.
Суть сабжевого проекта, как я понимаю, заменить неудачную макросистему C (ака #define) на более удачную плюс реализовать дополнительный анализ кода. В качестве примера использования макросистемы приводится реализация некой полезной библиотеки макросов. Соответственно, возникает вопрос: смогу ли я воспользоваться этой библиотекой из своего кода на C (допустим, для этого придется добавить дополнительный шаг в процесс сборки — но и фиг бы с ним) или вынужден буду переписать весь код на Lisp-C? Второй вариант кажется мне достаточно обидным.
Здравствуйте, Mr.Cat, Вы писали:
MC>Здравствуйте, A13x, Вы писали: A>>Чтобы иметь удобную возможность оперировать с кодом из lisp, опять же lisp-синтаксис (лично мне) кажется очень стройным и логичным. A>>S-выражения достаточны для описанной задачи, а так же универсальны и однотипны. MC>Я тоже люблю s-выражения, но подозрительно отношусь к тому, чтобы насаждать s-выражения там, где их изначально не было. MC>Суть сабжевого проекта, как я понимаю, заменить неудачную макросистему C (ака #define) на более удачную плюс реализовать дополнительный анализ кода. В качестве примера использования макросистемы приводится реализация некой полезной библиотеки макросов. Соответственно, возникает вопрос: смогу ли я воспользоваться этой библиотекой из своего кода на C (допустим, для этого придется добавить дополнительный шаг в процесс сборки — но и фиг бы с ним) или вынужден буду переписать весь код на Lisp-C? Второй вариант кажется мне достаточно обидным.
Не знаю в таких деталях предлагаемого автором синтаксиса, но было бы нелепо лишать пользователей библиотеки возможности подключать свои файлы — не предусмотрев что-то типа (include "mylib.h").
Кстати, указанного недостатка не лишен любой другой синтаксис кроме С-подобного, т.к. возможность переиспользования имеющихся библиотек все равно заставит так или иначе описывать экспортируемые сущности.
Возникает вопрос — как делать проверки на экспортируемые из mylib.h функции и типы?
Тут есть варианты:
— просто игнорировать, для чего после пользователю нужно будет еще описать игнорируемые значения (что есть не очень хорошо, но просто и понятно).
— заставить пользователя описать, что находится в mylib.h (чревато ошибками при изменении структурного содержания экспортируемых сущностей).
— парсить mylib.h и выдирать описания структур и типов (только как быть с дефайнами? вообще можно и тут что то придумать , например, предлагать писать (include "mylib.h" (defines (ARCH "x86") (MY_BLOCK_SIZE 14))))
Здравствуйте, A13x, Вы писали: A>Не знаю в таких деталях предлагаемого автором синтаксиса, но было бы нелепо лишать пользователей библиотеки возможности подключать свои файлы — не предусмотрев что-то типа (include "mylib.h").
Я про наоборот. Можно ли будет из уже написанного кода на C вызвать макрос, написанный на сабжевом лиспе.
Здравствуйте, A13x, Вы писали:
A>Не знаю в таких деталях предлагаемого автором синтаксиса, но было бы нелепо лишать пользователей библиотеки возможности подключать свои файлы — не предусмотрев что-то типа (include "mylib.h").
Автор упоминал про предполагаемую возможность подключения сторонних Си-библиотек. Писал что-то в духе "нужно будет импортировать определения типов данных и функций в персистентное хранилище отдельной утилитой — и в путь: дальше амплифаер без всяких инклудов будет вставлять потребные описания по мере необходимости."
Здравствуйте, Mr.Cat, Вы писали:
MC>Здравствуйте, A13x, Вы писали: A>>Не знаю в таких деталях предлагаемого автором синтаксиса, но было бы нелепо лишать пользователей библиотеки возможности подключать свои файлы — не предусмотрев что-то типа (include "mylib.h"). MC>Я про наоборот. Можно ли будет из уже написанного кода на C вызвать макрос, написанный на сабжевом лиспе.
Собственно макрос, конечно, не вызвать. Но можно будет вызвать функцию, в которую этот макрос развернётся. Нужно только будет заставить амплифаер генерировать соответствующие заголовочные файлы. Или типа того.
Здравствуйте, yumi, Вы писали: Y>Нужен или нет, каждый сам для себя решает
Я вот пробую принять сторону тех, кто решил, что не нужен.
Y>Лиспосинтаксис aka s-expressions проще, в том смысле, что ими проще манипулировать, трансформировать, ведь это и есть по сути AST. В немерле уже сложнее, в основном видимо из-за наличия синтаксиса, многостадийности компиляции и нескольких AST на разных стадиях компиляции. Например, точно не помню, очень примерно, на этапе лексического анализа используется PreParse tree, далее, ParseTree, потом TypedTree, как-то так. Т.е. внутри макроса, мы должны знать, на каком этапе мы и какое дерево нам доступно.
Ну раз есть макросы, манипулирующие TypedTree — значит макросы знают о статической типизации (которой в cl/scheme/clojure какбы нет) и это в любом случае вызовет сложности. Это все-таки ортогонально представлению кода в s-выражениях.
Y>Можно сравнить на простых примерах.
Я немерле в достаточной мере не знаю, чтобы как-то прокомментировать твои примеры, но видится мне, что немерлейные макросы из примеров имеют больше возможностей. Из while торчат уши break и continue, а when видистя мне чем-то большим, нежели синонимом if (впрочем, он мне в первую очередь видится какой-то неведомой хреновиной).
Я вот пока для себя слабо представляю, почему макросистемы в языках, не онованных на s-exp-ах обяхательно будут сложнее/неудобнее/хуже/...
Вот взять к примеру plot (обсуждения гуглятся по "PLOT: A non-parenthesized, infix Lisp!"). Автор его даже диалектом лиспа называет. А синтаксис у него питоноподобный (вспомнился boo, который еще можно было б приплести, но я его не знаю).
Здравствуйте, yumi, Вы писали:
Y>Т.е. внутри макроса, мы должны знать, на каком этапе мы и какое дерево нам доступно.
Для большенства вещей ParseTree хватает за глаза.
PreParse tree и TypedTree нужны когда хочется сделать что-то действительно навороченное.
Например грамматику задавать вот таким образом:
grammar
{
any = ['\u0000' .. '\uFFFF'];
letter = ['a' .. 'z'] / ['A' .. 'Z'] / '_';
digit = ['0' .. '9'];
spaces = ' '*;
id : Expr = (letter (digit / letter)*) spaces;
num : Expr = digit+ spaces;
expr' : Expr = '(' spaces sum ')' spaces;
expr : Expr = num / id / expr';
sum : Expr = expr ('+' spaces expr)* spaces;
start : Expr = spaces sum spaces !any;
}
Y>Можно сравнить на простых примерах.
Давай только сначала я вырежу из немерловах макросов тут функционал которого нет в макросах лиспа:
Здравствуйте, yumi, Вы писали:
Y>Теперь все фен-шую А что это за аццкие синтаксические штучки были? Какой функционал они добавляют?
while который сейчас выглядит так содержит код для того чтобы работали break и continue
Здравствуйте, yumi, Вы писали:
Y>Лиспосинтаксис aka s-expressions проще, в том смысле, что ими проще манипулировать, трансформировать, ведь это и есть по сути AST. В немерле уже сложнее, в основном видимо из-за наличия синтаксиса, многостадийности компиляции и нескольких AST на разных стадиях компиляции. Например, точно не помню, очень примерно, на этапе лексического анализа используется PreParse tree, далее, ParseTree, потом TypedTree, как-то так. Т.е. внутри макроса, мы должны знать, на каком этапе мы и какое дерево нам доступно.
Трасформация в немерле ведется только на ParseTree. Точнее во время типизации, перед превращением ParseTree в TypedTree. Но TypedTree использовать не обязательно. Он нужен только изредка для анализа типов. Это уже высший пилотаж. Лисп этого не поддерживает. В нем это просто бессмысленно, так как Лисп язык с динамической типизацией.
Y>Можно сравнить на простых примерах.
Y>Макрос when на Nemerle: Y>
Это не корректное сравнение, так как немерловый when гораздо мощьнее. Он по совместительству является гуардом (защитной конструкцией) и поддерживет паттерн-матчинг. Аналок when из лиспа будет выглядеть так:
На мой взгляд система квази-цитирования немерла намного понятнее и читабельнее нежели аналогичная в Комон Лисп.
Краткий курс немерловый макросов для лисперов
Квази-цитирование
Тип Comon Lisp Nemerle
Цитата кода `( цитируемый код ) <[ цитируемый код ]>
Вставка кода ,переменная $переменная
из переменной
(unquote)
Вставка кода ,@переменная ..$переменная
из списка
(unquote списка)
Очевидна, что разницы практически нет. Кроме того, что в немерле применяется полноценный синтаксис, а не безликие списки.
Еде одно приемущество немерла заключается в том, что его макросы гигиеничные. Это значит, что ты не можешь случайно захватить переменные из контекста в котором будет применяться макрос. В Комон Лисп, насколько я знаю, с этим полная задница. В Схеме гигиена есть, но она во много раз менее удобна.
Ну, вот уже близко по объему. Если учесть, что немерловый цикл поддерживает break и continue, так вообще все становится на свои места.
Кроме того это очень старая версия которую то ли писали с бодуна, то ли еще во времена когда гигиены не было. Вот так она выглядит сегодня:
Если он более эффективный, то это говорит о плохом качестве реализации лисп-машины. Ну, а то, что он проще, так в нем вообще не поддерживается прерывание цикла. Аналог на немерле:
Здравствуйте, WolfHound, Вы писали:
WH>В when накручена поддержка синтаксиса WH>
WH>when (asdasd is SomeType when blah-blah)
WH>{
WH> ...
WH>}
WH>
WH>зачем не знаю
Затем же зачем в лиспе есть when при наличии if который может не иметь "else"-части — чтобы можно было не создавать match c пустым "! _ =>" и чтобы можно было делать нечто что в обероне называется type guard. Скажем так:
def o : option[strint] = Some("строка");
when (o is Some(value))
doStaf(value);
В value оказывается значение из Some, если "o" содержит Some.
Если в "o" оказывается None(), то управление не передается в when.
Аналогичный код с использованием match-а будет выглядеть так:
def o : option[strint] = Some("строка");
match (o)
{
| Some(value) => doStaf(value);
| _ => () // ничего не делаем!
}
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Code Digger, Вы писали:
CD>Лично меня интересует вопрос, далеко ли можно уехать на одних только compile-time макросах? Сила лиспа не в одних макросах заключена...
А можно перечислить то, что есть в Лиспе и нет, скажем в Немерле? Ну, кроме динамически компилируемых макросов.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.