Amplifying C
От: yumi  
Дата: 25.01.10 11:51
Оценка: 29 (5) -1 :)
Здесь.
Lisp is not dead. It’s just the URL that has changed:
http://clojure.org
Re: Amplifying C
От: Mr.Cat  
Дата: 25.01.10 12:12
Оценка:
Здравствуйте, yumi, Вы писали:
Y>Здесь.
Кстати, а нужен ли в итоге лиспосинтаксис? Я вот не очень знаком с nemerle и boo, но там есть макросы и без него.
Re[2]: Amplifying C
От: A13x США  
Дата: 25.01.10 13:10
Оценка:
Здравствуйте, 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 "и имеем уважение"(с)
Re: Amplifying C
От: A13x США  
Дата: 25.01.10 13:15
Оценка: 8 (1)
Здравствуйте, yumi, Вы писали:

Y>Здесь.




еще ссылка по теме для интересующихся: Google DSL
не совсем "amplifying C", но решает сходные задачи кодогенерации.
Re[2]: Amplifying C
От: yumi  
Дата: 25.01.10 13:22
Оценка:
Здравствуйте, Mr.Cat, Вы писали:

MC>Кстати, а нужен ли в итоге лиспосинтаксис? Я вот не очень знаком с nemerle и boo, но там есть макросы и без него.


Нужен или нет, каждый сам для себя решает
Лиспосинтаксис aka s-expressions проще, в том смысле, что ими проще манипулировать, трансформировать, ведь это и есть по сути AST. В немерле уже сложнее, в основном видимо из-за наличия синтаксиса, многостадийности компиляции и нескольких AST на разных стадиях компиляции. Например, точно не помню, очень примерно, на этапе лексического анализа используется PreParse tree, далее, ParseTree, потом TypedTree, как-то так. Т.е. внутри макроса, мы должны знать, на каком этапе мы и какое дерево нам доступно.

Можно сравнить на простых примерах.

Макрос when на Nemerle:
  macro whenmacro (cond, body)
  syntax ("when", "(", cond, ")", body) 
  {
    def res1 = match (cond)
    {
      | <[ $subCond is $pattren ]> with guard = null
      | <[ $subCond is $pattren when $guard ]> =>
        def res2 = match (pattren)
        {
          | PT.PExpr.Call when guard != null => 
            <[ match ($subCond) { | $pattren when $guard => $body : void | _ => () } ]>
          | PT.PExpr.Call => 
            <[ match ($subCond) { | $pattren => $body : void | _ => () } ]>
          | _ => <[ match ($cond) { | true => $body : void | _ => () } ]>
        }
        res2
      | _ => <[ match ($cond) { | true => $body : void | _ => () } ]>
    }
    res1
  }

(c) nemerle\macros\core.n

Макрос when на Lisp'e:
(defmacro when (condition &rest body)
  `(if ,condition (progn ,@body)))

(c) Practical Common Lisp by Peter Seibel

Макрос while на Nemerle:
  macro @while (cond, body)
  syntax ("while", "(", cond, ")", body) 
  {
    def loop = Nemerle.Macros.Symbol (Util.tmpname ("while_"));

    <[ 
      $("_N_break" : global) : {
        def $(loop : name) () : void {
          when ($cond) {
            $("_N_continue" : global) : {
              $body 
            } 
            $(loop : name) ()
          }
        } 
        $(loop : name) (); 
      }
    ]>
  }

(c) nemerle\macros\core.n

Макрос while на Lisp'e:
(defun while-function (predicate block)
  (if (not (funcall predicate)) (return))
  (funcall block)
  (while-function predicate block))  

(defmacro while (expression &body body)
  `(while-function (lambda () ,expression)
     (lambda () ,@body)))

(c) Pascal Constanza

или

более простой макрос, но более эффективный while на Lisp'e:
(defmacro while (expression &body body)
  `(tagbody
     start (if (not ,expression) (go end))
           ,@body
           (go start)
     end))

(c) Pascal Constanza
Lisp is not dead. It’s just the URL that has changed:
http://clojure.org
Re[2]: Amplifying C
От: yumi  
Дата: 25.01.10 13:37
Оценка:
Здравствуйте, A13x, Вы писали:

A>еще ссылка по теме для интересующихся: Google DSL

A>не совсем "amplifying C", но решает сходные задачи кодогенерации.

Сижу тихонько просматриваю исходники, и вижу:
     (method :my-method (return-type :string (doc "Return value.")) (public)
      (doc "This method does strange things.")


А если серьезно, то это некое тестовое определение метода.

ЗЫ: документации жаль никакой нет
Lisp is not dead. It’s just the URL that has changed:
http://clojure.org
Re[3]: Amplifying C
От: A13x США  
Дата: 25.01.10 13:55
Оценка:
Здравствуйте, yumi, Вы писали:

Y>...

Y>ЗЫ: документации жаль никакой нет

Это да.

Если серьезно — в прошлом году меня посещали схожие мысли, что и автора "Amplifying C".
В первую голову смотрел на cl-dsl, но он мне не очень понравился своей навороченностью, отсутствием документации и проработанным наборов юнит тестов.
В свободное время пытаюсь сделать нечто подобное, в чем то упростив, в чем то усложнив концепцию обработки DSL-кода.

Благо — это хороший способ изучить лисп вообще
Да и черновые прототипы подобных вещей делаются за буквально за несколько минут на clisp, в отличие от других ЯП.
Re[3]: Amplifying C
От: Mr.Cat  
Дата: 25.01.10 14:16
Оценка:
Здравствуйте, A13x, Вы писали:
A>Чтобы иметь удобную возможность оперировать с кодом из lisp, опять же lisp-синтаксис (лично мне) кажется очень стройным и логичным.
A>S-выражения достаточны для описанной задачи, а так же универсальны и однотипны.
Я тоже люблю s-выражения, но подозрительно отношусь к тому, чтобы насаждать s-выражения там, где их изначально не было.
Суть сабжевого проекта, как я понимаю, заменить неудачную макросистему C (ака #define) на более удачную плюс реализовать дополнительный анализ кода. В качестве примера использования макросистемы приводится реализация некой полезной библиотеки макросов. Соответственно, возникает вопрос: смогу ли я воспользоваться этой библиотекой из своего кода на C (допустим, для этого придется добавить дополнительный шаг в процесс сборки — но и фиг бы с ним) или вынужден буду переписать весь код на Lisp-C? Второй вариант кажется мне достаточно обидным.
Re[4]: Amplifying C
От: A13x США  
Дата: 25.01.10 14:44
Оценка:
Здравствуйте, 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))))
Re[5]: Amplifying C
От: Mr.Cat  
Дата: 25.01.10 15:03
Оценка:
Здравствуйте, A13x, Вы писали:
A>Не знаю в таких деталях предлагаемого автором синтаксиса, но было бы нелепо лишать пользователей библиотеки возможности подключать свои файлы — не предусмотрев что-то типа (include "mylib.h").
Я про наоборот. Можно ли будет из уже написанного кода на C вызвать макрос, написанный на сабжевом лиспе.
Re[5]: Amplifying C
От: Code Digger Грузия  
Дата: 25.01.10 16:15
Оценка:
Здравствуйте, A13x, Вы писали:

A>Не знаю в таких деталях предлагаемого автором синтаксиса, но было бы нелепо лишать пользователей библиотеки возможности подключать свои файлы — не предусмотрев что-то типа (include "mylib.h").


Автор упоминал про предполагаемую возможность подключения сторонних Си-библиотек. Писал что-то в духе "нужно будет импортировать определения типов данных и функций в персистентное хранилище отдельной утилитой — и в путь: дальше амплифаер без всяких инклудов будет вставлять потребные описания по мере необходимости."
Re[6]: Amplifying C
От: Code Digger Грузия  
Дата: 25.01.10 16:18
Оценка:
Здравствуйте, Mr.Cat, Вы писали:

MC>Здравствуйте, A13x, Вы писали:

A>>Не знаю в таких деталях предлагаемого автором синтаксиса, но было бы нелепо лишать пользователей библиотеки возможности подключать свои файлы — не предусмотрев что-то типа (include "mylib.h").
MC>Я про наоборот. Можно ли будет из уже написанного кода на C вызвать макрос, написанный на сабжевом лиспе.

Собственно макрос, конечно, не вызвать. Но можно будет вызвать функцию, в которую этот макрос развернётся. Нужно только будет заставить амплифаер генерировать соответствующие заголовочные файлы. Или типа того.
Re: Amplifying C
От: Code Digger Грузия  
Дата: 25.01.10 16:20
Оценка:
Здравствуйте, yumi, Вы писали:

Y>Здесь.


Лично меня интересует вопрос, далеко ли можно уехать на одних только compile-time макросах? Сила лиспа не в одних макросах заключена...
Re[3]: Amplifying C
От: Mr.Cat  
Дата: 25.01.10 18:20
Оценка: +1
Здравствуйте, 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, который еще можно было б приплести, но я его не знаю).
Re[3]: Amplifying C
От: WolfHound  
Дата: 26.01.10 11:12
Оценка:
Здравствуйте, 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>Можно сравнить на простых примерах.

Давай только сначала я вырежу из немерловах макросов тут функционал которого нет в макросах лиспа:

Макрос when на Nemerle:
  macro whenmacro (cond, body)
  syntax ("when", "(", cond, ")", body) 
  {
    <[ match ($cond) { | true => $body : void | _ => () } ]>
  }

Y>(c) nemerle\macros\core.n

Y>Макрос when на Lisp'e:

Y>
Y>(defmacro when (condition &rest body)
Y>  `(if ,condition (progn ,@body)))
Y>

Y>(c) Practical Common Lisp by Peter Seibel

Макрос while на Nemerle:
    macro @while (cond, body)
    syntax ("while", "(", cond, ")", body) 
    {
        <[ 
            def loop() : void {
                when ($cond) {
                    $body;
                    loop()
                }
            } 
            loop(); 
        ]>
    }


Y>Макрос while на Lisp'e:

Y>
Y>(defun while-function (predicate block)
Y>  (if (not (funcall predicate)) (return))
Y>  (funcall block)
Y>  (while-function predicate block))  

Y>(defmacro while (expression &body body)
Y>  `(while-function (lambda () ,expression)
Y>     (lambda () ,@body)))
Y>

Y>(c) Pascal Constanza

Y>или


Y>более простой макрос, но более эффективный while на Lisp'e:

Y>
Y>(defmacro while (expression &body body)
Y>  `(tagbody
Y>     start (if (not ,expression) (go end))
Y>           ,@body
Y>           (go start)
Y>     end))
Y>

Y>(c) Pascal Constanza
Ну как немерле все еще сложнее?
... << RSDN@Home 1.2.0 alpha 4 rev. 1305>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[4]: Amplifying C
От: yumi  
Дата: 26.01.10 13:15
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Ну как немерле все еще сложнее?


Теперь все фен-шую А что это за аццкие синтаксические штучки были? Какой функционал они добавляют?
Lisp is not dead. It’s just the URL that has changed:
http://clojure.org
Re[5]: Amplifying C
От: WolfHound  
Дата: 26.01.10 14:48
Оценка: 8 (1)
Здравствуйте, yumi, Вы писали:

Y>Теперь все фен-шую А что это за аццкие синтаксические штучки были? Какой функционал они добавляют?

while который сейчас выглядит так содержит код для того чтобы работали break и continue
  macro @while (cond, body)
  syntax ("while", "(", cond, ")", body) 
  {
    <[ 
      ($("_N_break" : global) : {
        def loop () : void
        {
          when ($cond)
          {
            ($("_N_continue" : global) : {
              $body
            }) : void;
            loop ()
          }
        } 
        
        loop (); 
      }) : void
    ]>
  }

Вот реализация break и continue
  macro Break ()  syntax ("break")
  {
    <[ $("_N_break" : global) () ]>
  }
  
  macro Continue ()  syntax ("continue")
  {
    <[ $("_N_continue" : global) () ]>
  }

Макры по умолчанию гигиеничны так что global нужен чтобы подавить гигиену.

В when накручена поддержка синтаксиса
when (asdasd is SomeType when blah-blah)
{
    ...
}

зачем не знаю
... << RSDN@Home 1.2.0 alpha 4 rev. 1305>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[3]: Amplifying C
От: VladD2 Российская Империя www.nemerle.org
Дата: 26.01.10 19:19
Оценка: 8 (1) -1
Здравствуйте, yumi, Вы писали:

Y>Лиспосинтаксис aka s-expressions проще, в том смысле, что ими проще манипулировать, трансформировать, ведь это и есть по сути AST. В немерле уже сложнее, в основном видимо из-за наличия синтаксиса, многостадийности компиляции и нескольких AST на разных стадиях компиляции. Например, точно не помню, очень примерно, на этапе лексического анализа используется PreParse tree, далее, ParseTree, потом TypedTree, как-то так. Т.е. внутри макроса, мы должны знать, на каком этапе мы и какое дерево нам доступно.


Трасформация в немерле ведется только на ParseTree. Точнее во время типизации, перед превращением ParseTree в TypedTree. Но TypedTree использовать не обязательно. Он нужен только изредка для анализа типов. Это уже высший пилотаж. Лисп этого не поддерживает. В нем это просто бессмысленно, так как Лисп язык с динамической типизацией.

Y>Можно сравнить на простых примерах.


Y>Макрос when на Nemerle:

Y>
Y>  macro whenmacro (cond, body)
Y>  syntax ("when", "(", cond, ")", body) 
Y>  {
Y>    def res1 = match (cond)
Y>    {
Y>      | <[ $subCond is $pattren ]> with guard = null
Y>      | <[ $subCond is $pattren when $guard ]> =>
Y>        def res2 = match (pattren)
Y>        {
Y>          | PT.PExpr.Call when guard != null => 
Y>            <[ match ($subCond) { | $pattren when $guard => $body : void | _ => () } ]>
Y>          | PT.PExpr.Call => 
Y>            <[ match ($subCond) { | $pattren => $body : void | _ => () } ]>
Y>          | _ => <[ match ($cond) { | true => $body : void | _ => () } ]>
Y>        }
Y>        res2
Y>      | _ => <[ match ($cond) { | true => $body : void | _ => () } ]>
Y>    }
Y>    res1
Y>  }
Y>

Y>(c) nemerle\macros\core.n

Y>Макрос when на Lisp'e:

Y>
Y>(defmacro when (condition &rest body)
Y>  `(if ,condition (progn ,@body)))
Y>

Y>(c) Practical Common Lisp by Peter Seibel

Это не корректное сравнение, так как немерловый when гораздо мощьнее. Он по совместительству является гуардом (защитной конструкцией) и поддерживет паттерн-матчинг. Аналок when из лиспа будет выглядеть так:
public macro When(condition, body)
syntax ("when", "(", condition, ")", body)
{
  <[ match ($condition)
     {
       | true  => $body
       | false => ()
     }
  ]>
}

На мой взгляд система квази-цитирования немерла намного понятнее и читабельнее нежели аналогичная в Комон Лисп.
Краткий курс немерловый макросов для лисперов
Квази-цитирование
Тип                 Comon Lisp             Nemerle

Цитата кода         `( цитируемый код )    <[ цитируемый код ]>

Вставка кода        ,переменная            $переменная
из переменной
(unquote)

Вставка кода        ,@переменная           ..$переменная
из списка 
(unquote списка)


Очевидна, что разницы практически нет. Кроме того, что в немерле применяется полноценный синтаксис, а не безликие списки.

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


Y>Макрос while на Nemerle:

Y>
Y>  macro @while (cond, body)
Y>  syntax ("while", "(", cond, ")", body) 
Y>  {
Y>    def loop = Nemerle.Macros.Symbol (Util.tmpname ("while_"));

Y>    <[ 
Y>      $("_N_break" : global) : {
Y>        def $(loop : name) () : void {
Y>          when ($cond) {
Y>            $("_N_continue" : global) : {
Y>              $body 
Y>            } 
Y>            $(loop : name) ()
Y>          }
Y>        } 
Y>        $(loop : name) (); 
Y>      }
Y>    ]>
Y>  }
Y>

Y>(c) nemerle\macros\core.n

Y>Макрос while на Lisp'e:

Y>
Y>(defun while-function (predicate block)
Y>  (if (not (funcall predicate)) (return))
Y>  (funcall block)
Y>  (while-function predicate block))  

Y>(defmacro while (expression &body body)
Y>  `(while-function (lambda () ,expression)
Y>     (lambda () ,@body)))
Y>

Y>(c) Pascal Constanza

Ну, вот уже близко по объему. Если учесть, что немерловый цикл поддерживает break и continue, так вообще все становится на свои места.
Кроме того это очень старая версия которую то ли писали с бодуна, то ли еще во времена когда гигиены не было. Вот так она выглядит сегодня:
  macro @while (cond, body)
  syntax ("while", "(", cond, ")", body) 
  {
    <[ 
      ($("_N_break" : global) : {
        def loop () : void
        {
          when ($cond)
          {
            ($("_N_continue" : global) : {
              $body
            }) : void;
            loop ()
          }
        } 
        
        loop (); 
      }) : void
    ]>
  }



Y>более простой макрос, но более эффективный while на Lisp'e:

Y>
Y>(defmacro while (expression &body body)
Y>  `(tagbody
Y>     start (if (not ,expression) (go end))
Y>           ,@body
Y>           (go start)
Y>     end))
Y>

Y>(c) Pascal Constanza

Если он более эффективный, то это говорит о плохом качестве реализации лисп-машины. Ну, а то, что он проще, так в нем вообще не поддерживается прерывание цикла. Аналог на немерле:
  macro @while (cond, body)
  syntax ("while", "(", cond, ")", body) 
  {
    <[ 
        def loop() 
        {
          when ($cond)
            $body

          loop();
        } 
        
        loop();
      }
    ]>
  }


После компиляции он будет переписан компиляторов в аналог сишного while-а, с соответствующей эффективности.

Так что, уважаемый, ты тут распространяешь неверные слухи.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[6]: Amplifying C
От: VladD2 Российская Империя www.nemerle.org
Дата: 26.01.10 19:28
Оценка:
Здравствуйте, 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);
  | _ => () // ничего не делаем!
}
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: Amplifying C
От: VladD2 Российская Империя www.nemerle.org
Дата: 26.01.10 19:32
Оценка:
Здравствуйте, Code Digger, Вы писали:

CD>Лично меня интересует вопрос, далеко ли можно уехать на одних только compile-time макросах? Сила лиспа не в одних макросах заключена...


А можно перечислить то, что есть в Лиспе и нет, скажем в Немерле? Ну, кроме динамически компилируемых макросов.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: Amplifying C
От: VladD2 Российская Империя www.nemerle.org
Дата: 26.01.10 19:35
Оценка:
Здравствуйте, yumi, Вы писали:

Y>Здесь.


Идея лучше чем препрцессор С, но все равно это препроцессор. Язык (Лисп) ничего не знает о том, что он обрабатывает. С (си) — это статически типизированный язык с богатым синтаксисом. Чтобы получить полный контроль над ним нужно иметь макросы работающие с АСТ С и имеющие возможность получать информацию о типах из компилируемой программы. Без этого — это мало отличается от текстового препроцессора.

В общем, все украдено до нас. В Темплэйт Хаскель и Немерле реализованы полноценные макросы. Не скажу за Темплейт Хаскель. Но в Немерле они работают.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: Amplifying C
От: yumi  
Дата: 27.01.10 03:54
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Так что, уважаемый, ты тут распространяешь неверные слухи.


О! Спасибо тебе и Wolfhound за то, что потратили свое время на развернутый и очень полный ответ. Теперь я понял, что мне нужно еще один подход к Немерлу сделать В связи с этим, первый же вопрос, каково нынешнее состояние под mono, поддерживает ли его кто под mono?
Lisp is not dead. It’s just the URL that has changed:
http://clojure.org
Re[5]: Amplifying C
От: VladD2 Российская Империя www.nemerle.org
Дата: 27.01.10 06:55
Оценка:
Здравствуйте, yumi, Вы писали:

Y>О! Спасибо тебе и Wolfhound за то, что потратили свое время на развернутый и очень полный ответ. Теперь я понял, что мне нужно еще один подход к Немерлу сделать В связи с этим, первый же вопрос, каково нынешнее состояние под mono, поддерживает ли его кто под mono?


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

Ну, и конечно под Линуксом единственное что можно получить — это редактор с подсветкой синтаксиса.

Положительный момент тут только один — сам компилятор значительно стабильнее чем интеграция с VS. Так что отрицательных эмоций будет меньше .

Если серьезно, то при наличии винды лучше воспользоваться интеграцией или ее бесплатным аналогом.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: Amplifying C
От: Code Digger Грузия  
Дата: 27.01.10 12:11
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, Code Digger, Вы писали:


CD>>Лично меня интересует вопрос, далеко ли можно уехать на одних только compile-time макросах? Сила лиспа не в одних макросах заключена...


VD>А можно перечислить то, что есть в Лиспе и нет, скажем в Немерле? Ну, кроме динамически компилируемых макросов.


Да мы тут про Amplifying C говорили, а не про Немерле. Тем более, что я и не знаю, что там есть в Немерле.
Re[4]: Amplifying C
От: VladD2 Российская Империя www.nemerle.org
Дата: 27.01.10 15:00
Оценка:
Здравствуйте, Code Digger, Вы писали:

VD>>А можно перечислить то, что есть в Лиспе и нет, скажем в Немерле? Ну, кроме динамически компилируемых макросов.


CD>Да мы тут про Amplifying C говорили, а не про Немерле. Тем более, что я и не знаю, что там есть в Немерле.


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

Меж тем в лиспе кроме макросов больше ничего интересного и нет. Лямбды и замыкания сейчас есть почти в любом языке.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: Amplifying C
От: Mr.Cat  
Дата: 27.01.10 15:25
Оценка:
Здравствуйте, VladD2, Вы писали:
VD>Меж тем в лиспе кроме макросов больше ничего интересного и нет. Лямбды и замыкания сейчас есть почти в любом языке.
Если говорить о лиспах в целом — code as data есть, например. Пусть даже это не фича, а философия.
Re[6]: Amplifying C
От: VladD2 Российская Империя www.nemerle.org
Дата: 27.01.10 16:50
Оценка:
Здравствуйте, Mr.Cat, Вы писали:

VD>>Меж тем в лиспе кроме макросов больше ничего интересного и нет. Лямбды и замыкания сейчас есть почти в любом языке.

MC>Если говорить о лиспах в целом — code as data есть, например. Пусть даже это не фича, а философия.

Такое ощущение, что кто-то не не читает, что пишут другие. Или не понимает, что они пишу. Речь шла о фичах ФП.

"code as data" — это макросы. Оное и в том же Немерле тоже есть.

Более того. К ФП это никакого отношения не имеет.

ЗЫ

Так все же можно привести пример того, что есть в Лиспе и нет ни в одном другом языке.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: Amplifying C
От: Курилка Россия http://kirya.narod.ru/
Дата: 27.01.10 17:04
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, Mr.Cat, Вы писали:


VD>>>Меж тем в лиспе кроме макросов больше ничего интересного и нет. Лямбды и замыкания сейчас есть почти в любом языке.

MC>>Если говорить о лиспах в целом — code as data есть, например. Пусть даже это не фича, а философия.

VD>Такое ощущение, что кто-то не не читает, что пишут другие. Или не понимает, что они пишу. Речь шла о фичах ФП.


Влад, по-моему ты подразумеваешь местами то, что другие прочитать в твоих постах не могут.
Я вот лично выше по топику что-то не нашёл упоминаний именно "фич ФП".
Re[5]: Amplifying C
От: Code Digger Грузия  
Дата: 27.01.10 17:46
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, Code Digger, Вы писали:


VD>>>А можно перечислить то, что есть в Лиспе и нет, скажем в Немерле? Ну, кроме динамически компилируемых макросов.


CD>>Да мы тут про Amplifying C говорили, а не про Немерле. Тем более, что я и не знаю, что там есть в Немерле.


VD>Ну, так разберись. Вопрос отпадут сами собой. Amplifying C — это конечно наколенная поделка. Тем не менее сам подход — использование макросов времени компиляции — очень даже жизнеспособный, и уехать на нем можно очень даже далеко.


А тебе что ни скажи — всё одно начинаешь Немерле рекламировать?
И не указывай мне, пожалуйста, в чём разбираться, а в чём — нет. И не "тыкай", будь любезен.
Re[7]: Amplifying C
От: Mr.Cat  
Дата: 27.01.10 18:18
Оценка:
Здравствуйте, VladD2, Вы писали:
VD>Такое ощущение, что кто-то не не читает, что пишут другие. Или не понимает, что они пишу. Речь шла о фичах ФП.
Ну так это... предупреждать надо.

VD>"code as data" — это макросы.

Ну... мне кажется, это нечто большее.
Re[8]: Amplifying C
От: VladD2 Российская Империя www.nemerle.org
Дата: 27.01.10 18:42
Оценка:
Здравствуйте, Курилка, Вы писали:

К>Влад, по-моему ты подразумеваешь местами то, что другие прочитать в твоих постах не могут.

К>Я вот лично выше по топику что-то не нашёл упоминаний именно "фич ФП".

Да, действительно. Это эффект "разорванного" во время ответа + ответа в несколько тем сразу. Приношу свои извининия.

Но по сути... Смотрим исходную цитату:
CD>Лично меня интересует вопрос, далеко ли можно уехать на одних только compile-time макросах? Сила лиспа не в одних макросах заключена...

Мой вопрос:
VD>А можно перечислить то, что есть в Лиспе и нет, скажем в Немерле? Ну, кроме динамически компилируемых макросов.

И совершенно неадекватный ответ на этот вопрос:
MC>Если говорить о лиспах в целом — code as data есть, например. Пусть даже это не фича, а философия.

"code as data" это то на чем основаны макросы, т.е. ответ противоречит вопросу.

Собственно далее я действительно малось домыслил. Дело в том, что Лисп является родоначальником ФП как такового. Вот только то, что в нем на сегодня есть, есть в большинстве языков поддерживающих ФП хотя бы на минимальном уровне. В Питоне и Шарпе уж точно не меньше ФП чем в Комон Лиспе (который по умолчанию подразумевается под словом "Лисп").
Говорить об императивных возможностях вообще нечего. Они были до Лиспа и есть почти везде.

Так что еще особенного есть в Лисе?
Я могу припомнить только совершеенно извращенческий синаксис. Точнее полное его отсутсвие.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[6]: Amplifying C
От: VladD2 Российская Империя www.nemerle.org
Дата: 27.01.10 18:45
Оценка:
Здравствуйте, Code Digger, Вы писали:

CD>А тебе что ни скажи — всё одно начинаешь Немерле рекламировать?


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

CD>И не указывай мне, пожалуйста, в чём разбираться, а в чём — нет. И не "тыкай", будь любезен.


Что до "тыкай", то тут на форумах так принято. Не нравится, не посещай. На вы тут обычно хамят.
В прочем, извините великодушно. С Вами, уважаемый, будем только на Вы.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[6]: Amplifying C
От: VladD2 Российская Империя www.nemerle.org
Дата: 27.01.10 18:51
Оценка:
Здравствуйте, Code Digger, Вы писали:

CD>А тебе что ни скажи — всё одно начинаешь Немерле рекламировать?


Лучше вместо того чтобы выпендриваться ответил бы на прямо поставленный вопрос. В чем же эта загадочная сила Лиспа кроме макросов? Что в нем такого есть, чего нет в других языках?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[8]: Amplifying C
От: VladD2 Российская Империя www.nemerle.org
Дата: 27.01.10 18:56
Оценка:
Здравствуйте, Mr.Cat, Вы писали:

VD>>"code as data" — это макросы.

MC>Ну... мне кажется, это нечто большее.

ОК. Опиши что там большее. Лучше с примерами.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[9]: Amplifying C
От: Mr.Cat  
Дата: 28.01.10 09:48
Оценка:
Здравствуйте, VladD2, Вы писали:
VD>ОК. Опиши что там большее. Лучше с примерами.
Навскидку различие в том, что в немерле (насколько я понял) выбирается набор определенных структур данных (те, что используются для формирования ast), чье внешнее представление нарекается корректным кодом.
В лиспе немного наоборот — внешнее представление любой струткуры данных потенциально является корректным кодом (с учетом немногочисленных ограничений имплементации и макросистемы). Как-то так.
Re[7]: Amplifying C
От: Code Digger Грузия  
Дата: 28.01.10 10:02
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, Code Digger, Вы писали:


CD>>А тебе что ни скажи — всё одно начинаешь Немерле рекламировать?


VD>Если тема касается поддержки метапрограммирования времени компиляции, и темболее лиспо-подобных макросов в статически типизированных языках, то Немерле, пожалуй единственно о чем говорить можно.


Лично мне интереснее в этой области поговорить про Template Haskell — монада там не для красного словца используется.


CD>>И не указывай мне, пожалуйста, в чём разбираться, а в чём — нет. И не "тыкай", будь любезен.


VD>Что до "тыкай", то тут на форумах так принято. Не нравится, не посещай. На вы тут обычно хамят.

VD>В прочем, извините великодушно. С Вами, уважаемый, будем только на Вы.

Благодарю. На Вы мне общаться как-то привычнее, а то вспылил в прошлом комменте, за что прошу прощения.
Re[7]: Amplifying C
От: Code Digger Грузия  
Дата: 28.01.10 10:11
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, Code Digger, Вы писали:


CD>>А тебе что ни скажи — всё одно начинаешь Немерле рекламировать?


VD>Лучше вместо того чтобы выпендриваться ответили бы на прямо поставленный вопрос. В чем же эта загадочная сила Лиспа кроме макросов? Что в нем такого есть, чего нет в других языках?


Вообще-то, вопрос не ко мне. Я не настолько хорошо знаю Лисп, и не знаю Немерле, про который был вопрос.
Не могу сказать, в фичах ли языка тут дело, или в манере программирования, точнее, том, что на Лиспе изобретались и обкатывались самые разные парадигмы программирования, но если сравнить, например, CLOS и MOP с любой другой объектной системой, то становится немного странно от того, насколько легко и тонко можно расширять CLOS. И даже без макросов.
Re[4]: Amplifying C
От: A13x США  
Дата: 28.01.10 11:11
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>

VD>Еде одно приемущество немерла заключается в том, что его макросы гигиеничные. Это значит, что ты не можешь случайно захватить переменные из контекста в котором будет применяться макрос. В Комон Лисп, насколько я знаю, с этим полная задница. В Схеме гигиена есть, но она во много раз менее удобна.

вы плохо осведомлены о Common Lisp-е.

1) чтобы "случайно" не захватывать контекст придуман gensym, что то вроде такого:

(defmacro do-primes ((var start end) &body body)
  (let ((ending-value-name (gensym)))
    `(do ((,var (next-prime ,start) (next-prime (1+ ,var)))
          (,ending-value-name ,end))
         ((> ,var ,ending-value-name))
       ,@body)))


проверять это можно элементарно в REPL развертывая макрос через macroexpand-1, macroexpand и проч.


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

VD>После компиляции он будет переписан компиляторов в аналог сишного while-а, с соответствующей эффективности.

SBCL — компилирует в машинный код, причем по скорости он будет сравним с C. В функциях можно задавать типы аргументов (через declare).
Функции (в их defmethod ипостаси) могут быть описаны с указанием возможных типов и даже возможных значений:

(defmethod print-c ((statement p-qualified-type) stream) ... )

(defmethod parse-type-decl (context (id (eql 'struct)) args) ... )



А по поводу неудобства и "безликости" списков — это ваше личное мнение.
Лично мне Lisp видится намного более логичным и элегантным, чем Nemerle.
Re[4]: Amplifying C
От: Mr.Cat  
Дата: 28.01.10 11:15
Оценка:
Здравствуйте, VladD2, Вы писали:
VD>В Схеме гигиена есть, но она во много раз менее удобна.
Чем же?
Re[5]: Amplifying C
От: Mr.Cat  
Дата: 28.01.10 11:23
Оценка: +1
Здравствуйте, A13x, Вы писали:
A>1) чтобы "случайно" не захватывать контекст придуман gensym, что то вроде такого:
Еще один аспект гигиены — после раскрытия макроса ссылки (ну имена функций и переменных например) должны указывать туда, куда они указывают в месте объявления макроса, а не в месте использования (т.е. макросистема должна знать о системе модулей — например, вот так).
Re[7]: Amplifying C
От: A13x США  
Дата: 28.01.10 13:39
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>...

VD>Лучше вместо того чтобы выпендриваться ответил бы на прямо поставленный вопрос. В чем же эта загадочная сила Лиспа кроме макросов? Что в нем такого есть, чего нет в других языках?

Я не спец в lisp-е, но лично мне очевидны следующие преимущества:
1) Концепция "код как данные". Возможность конструировать программу буквально на лету (подход на макросах или для собственных DSL — через read/eval). В таком виде как у lisp нет нигде, насколько я знаю.
2) Универсальный, очень простой и очень мощный синтаксис, в котором все представляется атомами и s-выражениями (элементы типа ' или #' не в счет, это синтаксический сахар к (quote X), (function X)).
3) Очень мощная и расширяемая объектная система CLOS. C# второй и третей версии, например, не поддерживает мультиметодов. В общем, можно сказать что он и близко не стоял с CLOS.
4) Удобный REPL (есть во многих ФП, но не везде, например, насколько я знаю, в C# нету).
5) Можно использовать преимущества как динамической, так и статической типизации.
...

На эту тему написано довольно много — google "why lisp". Хотя бы это или вот это.

P.S. макросы в Common Lisp не предназначены для анализа типов. Образно говоря они работают до интерпретации/компиляции программы.
И это скорее хорошо, чем плохо — т.к. выражения, которые они генерируют могут быть использованы для самых разных целей. Если очень хочется то можно вставить и возможность определения типов типизацию, в зависимости от целей.
defmethod/defgeneric — это макросы, однако defmethod вносит возможность определять мультиметоды. В этом смысле можно считать, что анализ типа можно ввести и в lisp.
Причем ввести таким образом, как это будет нужно разработчику программы, а не lisp-компилятора.
Re[10]: Amplifying C
От: VladD2 Российская Империя www.nemerle.org
Дата: 28.01.10 13:53
Оценка:
Здравствуйте, Mr.Cat, Вы писали:

VD>>ОК. Опиши что там большее. Лучше с примерами.

MC>Навскидку различие в том, что в немерле (насколько я понял) выбирается набор определенных структур данных (те, что используются для формирования ast), чье внешнее представление нарекается корректным кодом.
MC>В лиспе немного наоборот — внешнее представление любой струткуры данных потенциально является корректным кодом (с учетом немногочисленных ограничений имплементации и макросистемы). Как-то так.

Это набор заблуждений.
Начнем с того, что в Лиспе не всякая структура данных может быть представлен как код. Вот пример такого списка — ("text" 1 2).

Вся разница между немерлом и лиспом по существу заключается в том, что в лиспе убогий синтаксис, что облегчает представление кода в виде данных. Но и там, и там для представления кода в виде данных используется один и тот же механизм — квази-цитирование. Этот механизм позволяет взять код в "ковычки" (в лисе это `( ... ), а в немерле <[ ... ]>) и получить на выходе структуру данных описывающую код. Кавычки могут иметь места-заполнители в которых может находиться код формирующих части формируемой структуры (для лиспа это ,( ... ), для немерла $( ... )).
Так что все практически идентично. И Лисп и Немерле позволяют представлять код в виде данных и манипулирвоать им.

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

В любом случае для обработки кода представленного в виде данных можно использовать всю мощь языка (функции работы со списками, замыкания, другие макросы, ...).
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[8]: Amplifying C
От: VladD2 Российская Империя www.nemerle.org
Дата: 28.01.10 13:58
Оценка:
Здравствуйте, Code Digger, Вы писали:

CD>Лично мне интереснее в этой области поговорить про Template Haskell — монада там не для красного словца используется.


Поговорите. Кстати, Template Haskell был прототипом Немерле. Монады там в общем-то не причем. Они в хаскеле нужны в не малой мере именно потому, что это средство позволяющее организовать императивное программирование в языке с ленивой семантикой. Так что к данной теми они отношения не имеют. Обработка кода не требует их применения.

CD>Благодарю. На Вы мне общаться как-то привычнее, а то вспылил в прошлом комменте, за что прошу прощения.


Что поделаешь? Как говорится — "В чужой монастырь со своим уставом со своим уставом ...".
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[8]: Amplifying C
От: VladD2 Российская Империя www.nemerle.org
Дата: 28.01.10 14:05
Оценка:
Здравствуйте, Code Digger, Вы писали:

CD>Вообще-то, вопрос не ко мне. Я не настолько хорошо знаю Лисп, и не знаю Немерле, про который был вопрос.

CD>Не могу сказать, в фичах ли языка тут дело, или в манере программирования, точнее, том, что на Лиспе изобретались и обкатывались самые разные парадигмы программирования, но если сравнить, например, CLOS и MOP с любой другой объектной системой, то становится немного странно от того, насколько легко и тонко можно расширять CLOS. И даже без макросов.

Я не заметил в MOP и созданном на его основе CLOS что-то действительно ценное. Более того я так и не нашел ни одного проекта где бы CLOS использовался на практике. Несомненно они есть, то похоже использование лиспа без CLOS намного более распространенное явление.

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

Единственное что есть в CLOS интересного — это мультиметоды. Но у них есть не мало своих проблем. Они тоже решение динамическое и плохо совместимое с компонентной природой дотнета (и вообще, современных систем). В то же время семантически паттерн-матчинг прекрасно заменяет мультиметоды. Кроме того их можно создать просто на базе динамических свойств дотнета.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: Amplifying C
От: VladD2 Российская Империя www.nemerle.org
Дата: 28.01.10 14:27
Оценка:
Здравствуйте, A13x, Вы писали:

A>вы плохо осведомлены о Common Lisp-е.


Я не скажу, что я знаток Комон Лиспа, но все же кое что в нем понимаю.

A>1) чтобы "случайно" не захватывать контекст придуман gensym, что то вроде такого:


A>
A>(defmacro do-primes ((var start end) &body body)
A>  (let ((ending-value-name (gensym)))
A>    `(do ((,var (next-prime ,start) (next-prime (1+ ,var)))
A>          (,ending-value-name ,end))
A>         ((> ,var ,ending-value-name))
A>       ,@body)))
A>


A>проверять это можно элементарно в REPL развертывая макрос через macroexpand-1, macroexpand и проч.


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

A>SBCL — компилирует в машинный код, причем по скорости он будет сравним с C.


Ну, начнем с того, что по крайней мере под Windows SBCL практически не существует. Сколько я его не смотрел он постоянно находится в состоянии альфа-версии и безбожно глючит.

Рассказы про то, что любой код переписывается в оптимальный маш.код и "будет сравним с C" — это не более чем миф.
Лисп имеет динамическую природу, по-умолчанию использует весьма не эффективные структуры данных (те же списки, к примеру). Но главное, что не отукда взять информацию о типах. Сколь нибудь серьзных систем вывода типов для Лиспа я не видел. Да и создать их проблематично, так как язык не проектировался под это (то что любой список может содержать разнотипные элементы уже препятствует эффективной компиляции). Так что скомпилировать в эффективный код можно или размеченный типами код, или очень примитивный.

A>В функциях можно задавать типы аргументов (через declare).


Вот именно. И после этого лисп уже становится не лиспом а жалкой породией на него. И это на фоне вывода типов и полной статической типизации того же немерла.
Сравненные явно не в пользу лиспа, не находишь?

A>Функции (в их defmethod ипостаси) могут быть описаны с указанием возможных типов и даже возможных значений:


A>
A>(defmethod print-c ((statement p-qualified-type) stream) ... )

A>(defmethod parse-type-decl (context (id (eql 'struct)) args) ... )
A>


Могут. Но в большинстве случаев не описываются.
Потом они могут взывать функции без описаний, что сводит на нет все усилия.
Учитывая, что вывода типов нет (по крайней мере в стандарте, да и подобных реализаций я не знаю), аннотировать придется все подряд. Но и это не избавляет от проблем вроде поддержки разнотипных значений списками.

A>А по поводу неудобства и "безликости" списков — это ваше личное мнение.


Это мнение 99% программистов, которые не выбирают лисп просто из-за скобок. Вот недавно его высказывали в форуме "Образование":
http://rsdn.ru/forum/education/3668807.1.aspx
Автор: VladD2
Дата: 14.01.10

Почитай. Весьма любопытно. За одно можешь убедиться, что как раз я то отношусь к лиспу очень с уважением и без предвзятости .

A>Лично мне Lisp видится намного более логичным и элегантным, чем Nemerle.


Ну, естественно. Если одно знаешь, а второе даже в глаза не видел, то по другому и быть не может.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: Amplifying C
От: VladD2 Российская Империя www.nemerle.org
Дата: 28.01.10 14:28
Оценка:
Здравствуйте, Mr.Cat, Вы писали:

VD>>В Схеме гигиена есть, но она во много раз менее удобна.

MC>Чем же?

Там обратная проблема. Чтобы ее преодалеть нужно раком встать. А иногда это нужно. В немерле же все просто. Есть набор идентификаторов позволяющих объяснить компилятору как интерпретировать символ.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[11]: Amplifying C
От: Mr.Cat  
Дата: 28.01.10 14:42
Оценка: -1
Здравствуйте, VladD2, Вы писали:
VD>Начнем с того, что в Лиспе не всякая структура данных может быть представлен как код.
Таки всякая.

VD>Вот пример такого списка — ("text" 1 2).

Это код. Честное слово код. Причем валидный. И я это чуть ниже продемонстрирую.
Как я говорил, это зависит от потрохов имплементации. По стандарту схемы получается что, да, валидные топлевелные выражения должны быть списками, у которых car — это символ. Т.е. по стандарту
("text" 1 2)

Это код, просто невалидный от рождения. Его вычисление валится с ошибкой.
А вот с тем, что вот это вполне вероятно валидный код — никто спорить не будет. Потому что семантика любых кододанных определяется самим программистом с небольшими ограничениями со стороны имплементации.
(f ("text" 1 2))

Идем дальше. Всеми любимая plt-scheme позволяет определять семантику любых структур данных. Например, я хочу, чтобы
("строка" символы ...)

вычислялось как форматирование символов строкой. Нет ничего проще. Берем и переопределяем в одном модуле форму #%app:
;sapp.scm
#lang scheme
(provide (except-out (all-from-out scheme) #%app)
         (rename-out [app #%app]))
(define-syntax-rule (app f x ...)
  ;; note that applications in the resulting pattern use our own
  ;; `#%app' implicitly
  (begin (if (string? f)
             (with-output-to-string (lambda () (printf f x ...)))
             (f x ...))))

А в другом — используем
;test.scm
#lang s-exp "sapp.scm"
("~s + ~s = ~s" 1 2 3) ;-> "1 + 2 = 3"

Вот так. Я, кстати, давал линк на статейку про это — но всем почему-то было как обычно.

VD>Кроме того в немерле в данных представляющих код (AST) имеется дополнительная информация.

Это опять же детали реализации, в scheme некоторые макросистемы (например, syntax-case) оперируют обертками над кододанными, какие-то — передают дополнительную информацию отдельно.

Насчет цитирования и по сабжу в целом:, как бы мне сделать, чтобы вот это стало валидной программой на немерле?
[f, 1, 2, 3]
Re[6]: Amplifying C
От: Mr.Cat  
Дата: 28.01.10 14:45
Оценка:
Здравствуйте, VladD2, Вы писали:
VD>Там обратная проблема. Чтобы ее преодалеть нужно раком встать. А иногда это нужно. В немерле же все просто. Есть набор идентификаторов позволяющих объяснить компилятору как интерпретировать символ.
Сорри, я ход твоих мыслей не уловил. Можно на примере (ну типа макры немерле против одной из макросистем схемы)?
Re[6]: Amplifying C
От: A13x США  
Дата: 28.01.10 14:56
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, A13x, Вы писали:


A>>вы плохо осведомлены о Common Lisp-е.


VD>Я не скажу, что я знаток Комон Лиспа, но все же кое что в нем понимаю.


A>>1) чтобы "случайно" не захватывать контекст придуман gensym, что то вроде такого:


A>>
A>>(defmacro do-primes ((var start end) &body body)
A>>  (let ((ending-value-name (gensym)))
A>>    `(do ((,var (next-prime ,start) (next-prime (1+ ,var)))
A>>          (,ending-value-name ,end))
A>>         ((> ,var ,ending-value-name))
A>>       ,@body)))
A>>


A>>проверять это можно элементарно в REPL развертывая макрос через macroexpand-1, macroexpand и проч.


VD>Да, я в курсе, что есть макросы позволяющие эмулировать гигиену с помощь самих же макросов. Только вот все это приседания цель которых обойти имеющуюся проблему. В Схеме и Немерле гигиена работает по умолчанию. И обратиться к внешнему контексту можно только намерено.


gensym — это функция, а не макрос. По поводу обращения к внешнему контексту — это спорно. Гигиена обеспечена? Обеспечена с помощью gensym. Остальное — лирика.

A>>SBCL — компилирует в машинный код, причем по скорости он будет сравним с C.


VD>Ну, начнем с того, что по крайней мере под Windows SBCL практически не существует. Сколько я его не смотрел он постоянно находится в состоянии альфа-версии и безбожно глючит.


Не SBCL-ом единым... Есть еще LispWorks, AllegroCL, CMUCL, CLISP...
Я, кстати, работаю с SBCL не на windows, так что для меня это не аргумент. На windows SBCL работает сносно уже несколько лет, несмотря на статус. Disclaimer оговаривает с чем могут возникнуть проблемы.

VD>Рассказы про то, что любой код переписывается в оптимальный маш.код и "будет сравним с C" — это не более чем миф.

VD>Лисп имеет динамическую природу, по-умолчанию использует весьма не эффективные структуры данных (те же списки, к примеру). Но главное, что не отукда взять информацию о типах. Сколь нибудь серьзных систем вывода типов для Лиспа я не видел. Да и создать их проблематично, так как язык не проектировался под это (то что любой список может содержать разнотипные элементы уже препятствует эффективной компиляции). Так что скомпилировать в эффективный код можно или размеченный типами код, или очень примитивный.

A>>В функциях можно задавать типы аргументов (через declare).


VD>Вот именно. И после этого лисп уже становится не лиспом а жалкой породией на него. И это на фоне вывода типов и полной статической типизации того же немерла.

VD>Сравненные явно не в пользу лиспа, не находишь? ...

Это уже спор о том, что лучше — динамическая типизация или статическая. Смысла нет обсуждать еще раз.
Кстати, никто не заставляет пихать списки куда не лень. Лисп может использовать вектор, хэш-таблицу, что угодно.
declare имеет смысл использовать в критических местах кода, в остальных проверка типа в рантайме не замедлит ощутимо работу программы.
Нужно обоснование на базе вывода профайлера.

defmethod как раз таки используется довольно часто именно в форме с указанием типов, в противном случае нет особого смысла его использовать и можно обойтись defun.
Re[8]: Amplifying C
От: VladD2 Российская Империя www.nemerle.org
Дата: 28.01.10 15:02
Оценка:
Здравствуйте, A13x, Вы писали:

A>Я не спец в lisp-е, но лично мне очевидны следующие преимущества:

A>1) Концепция "код как данные". Возможность конструировать программу буквально на лету (подход на макросах или для собственных DSL — через read/eval). В таком виде как у lisp нет нигде, насколько я знаю.

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

A>2) Универсальный, очень простой и очень мощный синтаксис, в котором все представляется атомами и s-выражениями


Полное отсутствие синтаксиса в угоду упрощения манипуляции кодом. Вот так будет проще.

A>(элементы типа ' или #' не в счет, это синтаксический сахар к (quote X), (function X)).


Да какая разница как цитаты называть? Хотя конечно никому в голову не придет quote использовать в реальном коде. Ну, а function и #' — это просто продолжение убогости синтаксис. В языках с синтаксисом такой маразм и не снился. В них любое имя функции уже ссылка на нее. А лямбда может передаваться в контекст где ожидается функция без всяких префиксов. Так что полноте убогость рекламировать.

A>3) Очень мощная и расширяемая объектная система CLOS. C# второй и третей версии, например, не поддерживает мультиметодов. В общем, можно сказать что он и близко не стоял с CLOS.


Опять сказка выдаваемая за действительность. Интерпретируемая, редко используемая, очень не похожая на привычный людям ООП. ООП нонче есть почти везде.

A>4) Удобный REPL (есть во многих ФП, но не везде, например, насколько я знаю, в C# нету).


О! Это тоже у нас преимущество лиспа?
А я его видел в хаскеле, F#-е, Скале, Немерле... Скоро будет в C#.

A>5) Можно использовать преимущества как динамической, так и статической типизации.

A>...

Не. Можно с серьезной болью в заднице использовать статическую типизацию. Вывода типов нет. Система типов CLOS является настройкой. В основной системе типов нет рефлексии и других полезных и современных вкосностей.

A>На эту тему написано довольно много — google "why lisp". Хотя бы это или вот это.


Да кто бы сомневался. 50 лет — это срок за который можно многое написать. Но люди его как-то не принимают.

A>P.S. макросы в Common Lisp не предназначены для анализа типов. Образно говоря они работают до интерпретации/компиляции программы.


Это преимущество?

A>И это скорее хорошо, чем плохо — т.к. выражения, которые они генерируют могут быть использованы для самых разных целей. Если очень хочется то можно вставить и возможность определения типов типизацию, в зависимости от целей.


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

A>defmethod/defgeneric — это макросы, однако defmethod вносит возможность определять мультиметоды. В этом смысле можно считать, что анализ типа можно ввести и в lisp.


Не. Мультиметоды — это совершенно динамическая фича. И потому весьма не эффективная.

A>Причем ввести таким образом, как это будет нужно разработчику программы, а не lisp-компилятора.


Ну, так в чем же это мифическое приемущество Лиспа? А CLOS? Дык он на макросах написан. В динамике? Дык а причем тут эффективность? Да и динамики у нас хоть пруд пруди. Руби и Питон очень динамичны. Причем они тоже компилируются (гы-гы).
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[12]: Amplifying C
От: VladD2 Российская Империя www.nemerle.org
Дата: 28.01.10 15:25
Оценка: -1
Здравствуйте, Mr.Cat, Вы писали:

VD>>Вот пример такого списка — ("text" 1 2).

MC>Это код. Честное слово код. Причем валидный. И я это чуть ниже продемонстрирую.

Не. Это структур данных которая кодом не является по определению. В лиспе есть понятия "форм лиспа". И данный список не подпадает под него, так как начинается не символа.

MC>Как я говорил, это зависит от потрохов имплементации.


Не. Это оговаривается стандартом Комон Лисп.

По стандарту схемы получается что, да, валидные топлевелные выражения должны быть списками, у которых car — это символ. Т.е. по стандарту
MC>
MC>;("text" 1 2)
MC>;

MC>Это код, просто невалидный от рождения. Его вычисление валится с ошибкой.
MC>А вот с тем, что вот это вполне вероятно валидный код — никто спорить не будет. Потому что семантика любых кододанных определяется самим программистом с небольшими ограничениями со стороны имплементации.
MC>
MC>;(f ("text" 1 2))
MC>;


Гы. Ты продемонстрировал, что данные и код в лиспе все таки тличаются.
Что и следовало доказать.
Ладно. Убеждать верующих отказаться от их религии дело не благодарное. Те кто способен к не предвзятому мышлению и так все поняли. На этом пожалуй и закончим.

MC>...Это опять же детали реализации, в scheme некоторые макросистемы (например, syntax-case) оперируют обертками над кододанными, какие-то — передают дополнительную информацию отдельно.


А кому нужен язык зависящий от деталей реализации? Тогда не надо говорить о Лиспе как о языке. Говори о конеретных компиляторах/интерпретаторах конкретных диалектов. Когда мне говорят Лисп, я понимаю это как Комон Лисп. У него конечно есть разные реализации, но они все подчиняются стандарту. И это замечательно!

MC>Насчет цитирования и по сабжу в целом:, как бы мне сделать, чтобы вот это стало валидной программой на немерле?

MC>
MC>[f, 1, 2, 3]
MC>

Если понимать "валидной программой" как это ты понимаешь, то ничего делать и не надо. Это и так допустимый код.

В любом конетесте он конечно не допустим, но не проблема сделать так, чтобы он был допустим где-то. Например, в Немерле поддерживает так называемый list comprehension. Вот, например, как реализована стандартная функция Filter в типе list[T]:
public Filter[T](this seq : SCG.IEnumerable[T], predicate : T -> bool) : list[T]
{
  $[ x | x in seq, predicate (x) ]
}


$[ x | x in seq, predicate (x) ] — list comprehension.
Конструкция практически аналогичная хаскелевской, за тем исключением, что это макрос реализованный в стандартной библиотеке макросов:
http://nemerle.googlecode.com/svn/nemerle/trunk/macros/Util.n
  macro ExpandListComprehension (params exprs : list [PExpr])
  {
    def adder =
      <[
         def cell = $(exprs.Head) :: [];
         if (head == null) {
           head = cell;
           tail = cell;
         } else {
           _N_skip_write_check (tail.tl) = cell;
           tail = cell;
         }
       ]>;
       
    def loops =
      exprs.Tail.Rev ().FoldLeft (adder,
        fun (e, acc) {
          match (ListComprehensionHelper.ExpandRange (e, acc)) {
            | Some (expr) => expr
               
            | None =>
              match (e) {
                | <[ $e1 in $e2 ]> =>
                  <[ foreach ($e1 in $e2) $acc ]>
                | cond =>
                  <[ when ($cond) $acc ]>
              }
          }
        });

    match (exprs) {
      | [<[ $second .. $last ]>] =>
        <[ $[ x | x in [$second .. $last]] ]>

      | [<[ $first ]>, <[ $second .. $last ]>] =>
        <[ $[ x | x in [$first, $second .. $last]] ]>
        
      | _ =>
        <[
            mutable head = null;
            mutable tail = null;
            $loops;
            if (head == null)
              []
            else
              head
        ]>
    }
  } 

  public module ListComprehensionHelper
  {
    [Nemerle.Macros.Hygienic]
    public ExpandRange (inrange : PExpr, acc : PExpr) : option [PExpr]
    {
      match (inrange) {
        | <[ $pat in $[$first, $second .. $last] ]>
        | <[ $pat in [$first, $second .. $last] ]> =>
          Some (<[
             mutable i = $first;
             mutable delta = $second - i;
             def last = $last;
             mutable cond = if (delta < 0) i >= last else i <= last;             
             def pre_last = unchecked (last - delta);
             
             when (delta < 0 && pre_last < last || delta > 0 && pre_last > last) // we overflowed
               delta = -delta;
               
             while (cond) {
               def $pat = i;
               if (delta < 0) 
                 cond = i >= pre_last;
               else 
                 cond = i <= pre_last;
               unchecked (i += delta);
               $acc;
             }
          ]>)
           
        | <[ $pat in $[$first .. $last] ]>
        | <[ $pat in [$first .. $last] ]> =>
          Some (<[
             mutable i = $first;
             def last = $last;
             mutable cond = i <= last;
             mutable pre_last = last;
             unchecked (pre_last--); // can't use (last - 1) since 1 might change/widen type
             def overflowed = pre_last > last;
             while (cond) {
               def $pat = i;
               if (overflowed)
                 cond = i >= pre_last;
               else
                 cond = i <= pre_last;
               unchecked (i++);
               $acc;
             }
          ]>)

        | _ => None ()
      }
    }
  }


Не проблема создать скажем @[ ... ] синтаксис который будет вести себя как-то иначе.

Кроме того в контексте другого макроса код может интерпретироваться вообще как угодно. Вольфхаунд уже приводил в этой теме пример EBNF синтаксиса реализованного на безе макросов немерла:
http://rsdn.ru/forum/decl/3681785.1.aspx
Автор: WolfHound
Дата: 26.01.10

Весь смысл в том, что макрос данных применяется внутри другого макроса. Вот как выглядит это в реальном коде:
  [PegGrammar(sum, 
  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;
  })]
  class TestSum
  {
    // обработчики вызываемые при разборе текста
  }


Макрос grammar предоставляет измененный синтаксис соответствующий PEG-натации (нечто вроде EBNF). Он применяется внутри так называемого мета-атрибута (PegGrammar в данном случае). Мета-атрибут — это нечто похожее на кастом-атрибуты в C#, но вместо того чтобы превращаться в метаинформацию закладываемую в сборку, в немерле они рассматриваются как макросы раскрывающиеся во время компиляции и позволяющие изменить код компилируемого модуля.

Вполне возможно было бы использовать его и в коде. Например, так:
def g = DefineGramar(  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;
  });

def result = g.Parse("1 + 2");


Так что никаких принципиальных проблем нет. И при этом нет нужды жить в спартанских условиях (писать код без синтаксиса).
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: Amplifying C
От: VladD2 Российская Империя www.nemerle.org
Дата: 28.01.10 15:32
Оценка:
Здравствуйте, Mr.Cat, Вы писали:

MC>Здравствуйте, VladD2, Вы писали:

VD>>Там обратная проблема. Чтобы ее преодалеть нужно раком встать. А иногда это нужно. В немерле же все просто. Есть набор идентификаторов позволяющих объяснить компилятору как интерпретировать символ.
MC>Сорри, я ход твоих мыслей не уловил. Можно на примере (ну типа макры немерле против одной из макросистем схемы)?

Скажем у нас есть имена "a", "b" и "c". Мы хотим чтобы "a" рассматривалось как глобальный символ (сопоставлялось бы только с символами из глобальных пространств имен), "b" находило бы символ динамически (т.е. брало сивол из любой области видимости доступный в момент раскрытия макроса), а "с" было был доступно только внутри макроса и не перекрывалось бы ни с какими именами. Тогда мы может написать цитату:
<[ $("a" : global) ...; $("b" : dyn) ....; c ...; /* или */ $("c" : name)]>

и компилятор сам все сделает. Да, "b" — это просто строка.
Кроме того есть API функции которые позволяют задать нужный контекст. Скажем если задать контекст используемый в компилируемом методе, то можно просто преодолеть гигиету и ссылаться на символы внутри контекста (т.е. как в Комон Лисп).
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: Amplifying C
От: VladD2 Российская Империя www.nemerle.org
Дата: 28.01.10 15:56
Оценка:
Здравствуйте, A13x, Вы писали:

A>gensym — это функция, а не макрос. По поводу обращения к внешнему контексту — это спорно. Гигиена обеспечена? Обеспечена с помощью gensym. Остальное — лирика.


Ага. Функция. Только на Комон Лиспе никто так не пишет. Это отличный путь получить дырявую макру.
Введение ending-value-name — это закат солнца в ручную. Нормальный программист напишет with-gensyms (как в той книжке откуда взять твой пример) и будет жить спокойно.
Если же вводить переименования вручную, то дыр в твоем коде будет столько, что он будет способен только на то, чтобы служить примером того как не надо писать код.

Собственно все эти приседания и делают Комон Лисп сложным для использования средним программистом.

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


A>Не SBCL-ом единым... Есть еще LispWorks, AllegroCL, CMUCL, CLISP...


Ага. Только когда заходит речь о компиляции, то SBCL — это единственно что можно привести в качестве примера. Остальные до него не дотягивают.

A>Я, кстати, работаю с SBCL не на windows, так что для меня это не аргумент. На windows SBCL работает сносно уже несколько лет, несмотря на статус. Disclaimer оговаривает с чем могут возникнуть проблемы.


Тогда поверь. Под виндой он глючит страшно. Я раза три пробовал его использовать (с большими промежутками). Каждый раз получал кучу проблем.

A>Это уже спор о том, что лучше — динамическая типизация или статическая. Смысла нет обсуждать еще раз.


Дык к вопросу скорости выполнения кода — это имеет прямое отношение. Динамика имеет свои недостатки. И попытка совместить вкусности из двух миров сравни попытки сидеть на двух стульях одновременно.

A>Кстати, никто не заставляет пихать списки куда не лень. Лисп может использовать вектор, хэш-таблицу, что угодно.


Ага. Только на практике везде списки. Скажем, список параметров переменной длинны — это автоматом список и не типизированный.
В немерле — это тоже, кстати, пролезло. Но все же, так как язык дотнетный, там действительно нет проблем использовать массивы и другие более эффективных для конкретных случаев типы.
Видимо списки это проклятие ФЯ. Их удобно использовать и из-за этого их суют во все дыры.

A>declare имеет смысл использовать в критических местах кода, в остальных проверка типа в рантайме не замедлит ощутимо работу программы.


Дык если у тебя 99% кода написано не эффективным образом, то появляется эффект интерпретатора. Многие задачи при том уже становятся недоступными. А если лепить типы везде, то становится неудобно. На мой взгляд язык с выводом типов и возможно возможностью перейти на динамику по желанию — это намного лучше.

A>Нужно обоснование на базе вывода профайлера.


Ну, вот мы и получаем в результате, что весь код который пишут на лиспе со временем переписывают на С. Почему тот же Emacs написан на С, и толко макросистема в нем на Лиспе?

A>defmethod как раз таки используется довольно часто именно в форме с указанием типов, в противном случае нет особого смысла его использовать и можно обойтись defun.


Ну, дык вот в Немерле и пошли дальше. В нем любые методы (т.е. глобальные функции и методы) обязаны быть обявлены с полным указанием типов или параметрами инициализированными константами, а внутри в кода методов поддерживается автоматический вывод типов. При этом гарантируется, что типы будут или полностью выведены, или будет выдана ошибка. Таким образом с одной стороны как и в лиспе в немерле не нужно всюду писать типы, но в отличии от лиспа в немерле всегда получается весьма эффективный код. От того на немерле можно писать те же редакторы кода целиком, а не только использовать его в качестве макросистемы.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[8]: Amplifying C
От: A13x США  
Дата: 28.01.10 22:35
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, A13x, Вы писали:


A>>gensym — это функция, а не макрос. По поводу обращения к внешнему контексту — это спорно. Гигиена обеспечена? Обеспечена с помощью gensym. Остальное — лирика.


VD>Ага. Функция. Только на Комон Лиспе никто так не пишет. Это отличный путь получить дырявую макру.

VD>Введение ending-value-name — это закат солнца в ручную. Нормальный программист напишет with-gensyms (как в той книжке откуда взять твой пример) и будет жить спокойно.
VD>Если же вводить переименования вручную, то дыр в твоем коде будет столько, что он будет способен только на то, чтобы служить примером того как не надо писать код.

Bопрос вкуса. Лично для меня более удобным является именно такой стиль написания. Да и необходимость в таких конструкциях не часто возникает. Однажды, когда мне нужно было написать довольно нетривиальный макрос, мне пришлось использовать форму с flet.

VD>Собственно все эти приседания и делают Комон Лисп сложным для использования средним программистом.


На работе я пишу на С++. И я бы не назвал С++ значительно более простым языком, чем Common Lisp.

Вдобавок, есть еще и личные предпочтения.
Мне вот так и не удалось осилить Python, просто не понравился синтаксис и как то забросил его. Perl осилил на уровне простых скриптов, чем временами пользуюсь, но без восторга. Впрочем всем оным я занимался, как и Lisp-ом, в свободное время, так что...

VD>Надо признать, что мары вообще писать не просто. Это ни каждому дано. Видимо, потому и языки с макросами не получают долной популярности.


Ну так программистом вообще говоря быть не просто. Для всего есть порог вхождения...
Уровень coding monkey доступен многим, но многим ли нужен такой работник? Вообще говоря, судя по требованиям, в некоторые русские компании ждут по меньшей мере второго Саттера или Страуструпа

A>>Не SBCL-ом единым... Есть еще LispWorks, AllegroCL, CMUCL, CLISP...


VD>Ага. Только когда заходит речь о компиляции, то SBCL — это единственно что можно привести в качестве примера. Остальные до него не дотягивают.


ну как минимум AllegroCL и CMUCL дотягивают.

Пример для Allegro из сети:
CL-USER> (declaim  (optimize speed
                             (safety 0)
                             (space 0)
                             (debug 0)))
T
CL-USER> (defun my-func (x)
           (declare (fixnum x))
           (the fixnum (1+ x)))
MY-FUNC
CL-USER> (compile 'my-func)
MY-FUNC
NIL
NIL
CL-USER> (disassemble 'my-func)
;; disassembly of #<Function MY-FUNC>
;; formals:

;; code start: #x2083517c:
   0: 83 c0 04    addl    eax,$4
   3: f8          clc
   4: 8b 75 fc    movl    esi,[ebp-4]
   7: c3          ret


SBCL генерирует почти такой же код (проверял у себя на x86-64 linux):

cl-user> (disassemble 'my-func)
; disassembly for my-func
; 034511BF:       4883C208         add rdx, 8
;       C3:       488BE5           mov rsp, rbp
;       C6:       F8               clc
;       C7:       5D               pop rbp
;       C8:       C3               ret


Что то сложное измышлять уже лень — ибо спать пора.

A>>Я, кстати, работаю с SBCL не на windows, так что для меня это не аргумент. На windows SBCL работает сносно уже несколько лет, несмотря на статус. Disclaimer оговаривает с чем могут возникнуть проблемы.


VD>Тогда поверь. Под виндой он глючит страшно. Я раза три пробовал его использовать (с большими промежутками). Каждый раз получал кучу проблем.


OK. LispWorks, AllegroCL? Для них есть техподдержка...

A>>...


A>>Кстати, никто не заставляет пихать списки куда не лень. Лисп может использовать вектор, хэш-таблицу, что угодно.


VD>Ага. Только на практике везде списки. Скажем, список параметров переменной длинны — это автоматом список и не типизированный...


Почему? Согласен, что списки используются не очень редко, но при необходимости нет никаких проблем использовать vector или hash-table.
Не вижу препятствий.

Кстати, а чем плохи списки?

A>>declare имеет смысл использовать в критических местах кода, в остальных проверка типа в рантайме не замедлит ощутимо работу программы.


VD>Дык если у тебя 99% кода написано не эффективным образом, то появляется эффект интерпретатора. Многие задачи при том уже становятся недоступными. А если лепить типы везде, то становится неудобно. На мой взгляд язык с выводом типов и возможно возможностью перейти на динамику по желанию — это намного лучше.


A>>Нужно обоснование на базе вывода профайлера.


VD>Ну, вот мы и получаем в результате, что весь код который пишут на лиспе со временем переписывают на С. Почему тот же Emacs написан на С, и толко макросистема в нем на Лиспе?


Как бы не 90% emacs написано на лисп (если сравнивать директории lisp и src в исходниках).

Не совсем понимаю тут термин "макросистема".
C помощью elisp emacs можно расширять очень и очень серьезно. Как пример можно взять тот же slime.
elisp не компилирует в машинный код (во всяком случае точно не в emacs), какие-то базовые части, понятно, надо было реализовывать на С. Не забываем, что emacs был написан довольно давно и требования по памяти и ресурсам были не в пример жестче чем сейчас.
На современном оборудовании абсолютно никаких тормозов я не замечал (средненький ноутбук — DELL двухгодовой давности), чего не сказать про 2008 студию даже со всеми отключенными плагинами на значительно более мощной машине.


A>>defmethod как раз таки используется довольно часто именно в форме с указанием типов, в противном случае нет особого смысла его использовать и можно обойтись defun.


VD>Ну, дык вот в Немерле и пошли дальше. В нем любые методы (т.е. глобальные функции и методы) обязаны быть обявлены с полным указанием типов или параметрами инициализированными константами, а внутри в кода методов поддерживается автоматический вывод типов. При этом гарантируется, что типы будут или полностью выведены, или будет выдана ошибка. Таким образом с одной стороны как и в лиспе в немерле не нужно всюду писать типы, но в отличии от лиспа в немерле всегда получается весьма эффективный код. От того на немерле можно писать те же редакторы кода целиком, а не только использовать его в качестве макросистемы.


OK, довод понятен.

В общем, если вопрос об эффективности встал ребром, почему бы не написать критические части на С? Сомневаюсь, что на Nemerle (и на Lisp, наверное, тоже) кто-нибудь написал x.264 кодек для промышленного использования или драйвер уровня ядра.
Если важна стратегия оптимального использования памяти — позволяет ли хоть какой-нибудь ФП реализовывать аллокатор для своих нужд?
В то, что таких ситуаций не бывает, уж простите, не поверю.

На уровне прикладных CRUD-style приложений выигрыш будет просто мизерным.

Вот и получается, что Nemerle вроде бы и в чем то эффективней Lisp, но как это использовать — непонятно.

И еще: известен ли вам проект, написанный на Lisp и переписанный на Nemerle, поработав с которым можно было бы сказать — "так, вот этот подонок тормозит, все срочно идем на Nemerle (Assembler, C, РЯП, нужное подчеркнуть)"?
Есть ли математическое обоснование того, что Nemerle будет, например в 2-4 раза эффективнее для такого-то класса задач на таких-то машинах чем какая-либо популярная реализация Common Lisp (или что-то другое)?
Re[8]: Amplifying C
От: Mr.Cat  
Дата: 29.01.10 10:26
Оценка:
Здравствуйте, VladD2, Вы писали:
VD>Скажем у нас есть имена "a", "b" и "c". Мы хотим чтобы "a" рассматривалось как глобальный символ (сопоставлялось бы только с символами из глобальных пространств имен), "b" находило бы символ динамически (т.е. брало сивол из любой области видимости доступный в момент раскрытия макроса), а "с" было был доступно только внутри макроса и не перекрывалось бы ни с какими именами. Тогда мы может написать цитату:
VD>
VD><[ $("a" : global) ...; $("b" : dyn) ....; c ...; /* или */ $("c" : name)]>
VD>

VD>и компилятор сам все сделает. Да, "b" — это просто строка.

Ну это примерно то же самое, что и в syntax-case: по умолчанию создаваемые макросом символы не перекрываются ни с какими именами, а используемые ссылки относятся к области видимости в месте объявления макроса. По необходимости это ломается, благодаря параметру у datum->syntax, указывающему, откуда для вводимого символа унаследовать "контекст".
Вот классическая копипаста из r6rs (макрос создает внутри блока кода неявный биндинг):
(define-syntax loop
  (lambda (x)
    (syntax-case x ()
      [(k e ...)
       (with-syntax
          ([break (datum->;syntax #’k ’break)]) ;Прошу прощения за вставленный форматтером коммент после стрелки, там его быть не должно
          #’(call-with-current-continuation
              (lambda (break)
                (let f () e ... (f)))))])))

(let ((n 3) (ls ’()))
  (loop
  (if (= n 0) (break ls))
  (set! ls (cons ’a ls))
  (set! n (- n 1))))


В данном случае, кстати, видно, что цитирование в немерле — это аналог не лиспового цитирования, а создания синтаксических объектов в схемском syntax-case: syntax-quote (ака #'), datum->syntax и т.п.
Re[6]: Amplifying C
От: yumi  
Дата: 29.01.10 10:59
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Под Моно все не очень радостно. Сборки компилятора вроде бы работают если их просто скопировать. Но собрать сам компилятор под Моно похоже нельзя из-за ошибок в самом Моно. Их обещали поправить, но похоже так этого и не сделали.


Жаль. Как раз, один мой проект, кастомер просит перевести под Моно. Значит не судьба, ну это и к лучшему, перепишу на Питоне, так будет гораздо быстрее.

VD>Ну, и конечно под Линуксом единственное что можно получить — это редактор с подсветкой синтаксиса.


Моно, это не только Линукс, это "Линукс в том числе".
Lisp is not dead. It’s just the URL that has changed:
http://clojure.org
Re[13]: Amplifying C
От: Mr.Cat  
Дата: 29.01.10 11:21
Оценка:
Здравствуйте, VladD2, Вы писали:
VD>Гы. Ты продемонстрировал, что данные и код в лиспе все таки тличаются.
Хз, я уже показал, как в plt управлять семантикой выражений. Что еще тебе нужно — я не знаю.

VD>Не. Это структур данных которая кодом не является по определению. В лиспе есть понятия "форм лиспа". И данный список не подпадает под него, так как начинается не символа.

VD>Не. Это оговаривается стандартом Комон Лисп.
VD>Когда мне говорят Лисп, я понимаю это как Комон Лисп.
Я понимаю, что ты евангелируешь немерле и тебе хочется конкретный, можно сказать, продукт сравнивать не с чьим-то абстрактным пониманием лиспа, а с конкретным продуктом. Но нет, я не коммонлиспер — и это без меня. Впрочем, есть одна plt scheme...

VD>$[ x | x in seq, predicate (x) ] — list comprehension.

VD>Конструкция практически аналогичная хаскелевской, за тем исключением, что это макрос реализованный в стандартной библиотеке макросов:
VD>Не проблема создать скажем @[ ... ] синтаксис который будет вести себя как-то иначе.
VD>Кроме того в контексте другого макроса код может интерпретироваться вообще как угодно.
Ага, т.е. в немерле можно прямо посреди текста программы писать код на произвольном, определенном разработчиком языке, типа
basic(
  10 SIN
  20 GOTO HELL)

Соответственно, возникают вопросы:
1. Как в случае компрехеншена компилятор понимает, каким макросом его обрабатывать?
2. Как компилятор понимает, что внутри использования некоего макроса нужно переключиться на другую грамматику (а потом и переключиться обратно)? Он ведь в процессе разбора текста должен как-то понять, что basic — это использование макроса и переключиться на другую грамматику.

VD>Так что никаких принципиальных проблем нет. И при этом нет нужды жить в спартанских условиях (писать код без синтаксиса).

Это не спартанские условия. Просто некоторые тут страдают скобкофобией разной степени тяжести.
Re[9]: Amplifying C
От: Mr.Cat  
Дата: 29.01.10 11:57
Оценка:
Здравствуйте, A13x, Вы писали:
A>На современном оборудовании абсолютно никаких тормозов я не замечал (средненький ноутбук — DELL двухгодовой давности), чего не сказать про 2008 студию даже со всеми отключенными плагинами на значительно более мощной машине.
Это потому что оборудование современное и в целом за перфомансом в емаксе вроде следят. Одно время в 23-й ветке (когда она еще не была релизом) были заметные тормоза при скроллинге, особенно при уменьшенной частоте процессора (сейчас 800MHz обычно минимальная).

A>В общем, если вопрос об эффективности встал ребром, почему бы не написать критические части на С? Сомневаюсь, что на Nemerle (и на Lisp, наверное, тоже) кто-нибудь написал x.264 кодек для промышленного использования или драйвер уровня ядра.

Так об этом и ветка. Amplifying, блин, C. Потому что C — плохой, неудобный язык — и в рамках отдельно взятого проекта (мои впечатления от ядра линукса) рано или поздно превращается в страшнолисп с абьюзом #define, замыканиями (нестандартная фича gcc), связными списками и т.п. Вот и возникает у людей идея о лиспоси — как лисп, только си, ну или как си, только лисп. Как-то так.
Re[9]: Amplifying C
От: VladD2 Российская Империя www.nemerle.org
Дата: 29.01.10 15:39
Оценка:
Здравствуйте, A13x, Вы писали:

A>Bопрос вкуса. Лично для меня более удобным является именно такой стиль написания. Да и необходимость в таких конструкциях не часто возникает. Однажды, когда мне нужно было написать довольно нетривиальный макрос, мне пришлось использовать форму с flet.


Это вопрос надежности программы, а не вкуса.

VD>>Собственно все эти приседания и делают Комон Лисп сложным для использования средним программистом.


A>На работе я пишу на С++. И я бы не назвал С++ значительно более простым языком, чем Common Lisp.


С++ настолько несуразный язык, что на его фоне многое можно оправдать.

A>Вдобавок, есть еще и личные предпочтения.


Ну, вот они и имею место в твоем случае.
A>ну как минимум AllegroCL и CMUCL дотягивают.

A>Пример для Allegro из сети:

A>
A>CL-USER> (declaim  (optimize speed
A>                             (safety 0)
A>                             (space 0)
A>                             (debug 0)))
A>T
A>CL-USER> (defun my-func (x)
A>           (declare (fixnum x))
A>           (the fixnum (1+ x)))
A>MY-FUNC
A>CL-USER> (compile 'my-func)
A>MY-FUNC
A>NIL
A>NIL
A>CL-USER> (disassemble 'my-func)
A>;; disassembly of #<Function MY-FUNC>
A>;; formals:

A>;; code start: #x2083517c:
A>   0: 83 c0 04    addl    eax,$4
A>   3: f8          clc
A>   4: 8b 75 fc    movl    esi,[ebp-4]
A>   7: c3          ret
A>


О! Супер. Великое достижение человечества. Функция инкремента быал скомпилирована в 4 маш-инструкции. Для сравнения берем аналогичный код на Немерле:
module Program
{
  Inc(x : int) : int { x + 1 }
  
  Main() : void
  {
    WriteLine(Inc(5));
  }
}

Смотрим результат в функции Main:
0000000b  mov         ecx,6 
00000010  call        FFFFFFFFEF5EDD40

Надеюсь ясно почему код приходится смотреть в функции Main?

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

В прочем, даже на подобном примере ты продемонстрировал явно низкое качество кодогенерации.

A>SBCL генерирует почти такой же код (проверял у себя на x86-64 linux):


A>Почему? Согласен, что списки используются не очень редко, но при необходимости нет никаких проблем использовать vector или hash-table.


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

A>Не вижу препятствий.


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

A>Кстати, а чем плохи списки?


Не экономным расходом памяти и неравномерным распределением по памяти. К тому же эффективный у них только добавление в начало списка. Добавление в середину или конец (не говоря уже о соединение списков) крайне не эффективны.

A>Как бы не 90% emacs написано на лисп (если сравнивать директории lisp и src в исходниках).


В емаксе на С написан сам код редактора (буферы и их изменение). Остальное уже не требует высокой производительности и эффективного хранения данных.

A>В общем, если вопрос об эффективности встал ребром, почему бы не написать критические части на С?


А зачем мне писать что-то на С? На том же немерле я получаю действительно близкую к С скорость, синтаксические макросы, понятный и удобный синтаксис и огромную библиотеку дотнета.
Зачем мне вместо этого использовать убогий в синтаксическом плане Лисп, да еще в паре с ужасно низкоуровневым С?

Сомневаюсь, что на Nemerle (и на Lisp, наверное, тоже) кто-нибудь написал x.264 кодек для промышленного использования или драйвер уровня ядра.

Драйвер ядра можно, но если сама ОС управляемая. Для винды и линукса конечно проблематично. А для ОС вроде Сингулярити вполне можно. Жаль что она пока не майнстрим.

Кодек более чем можно. Хотя некоторые его части действительно имеет смысл оптимизировать, только на на С, а на ассемблере.

A>Вот и получается, что Nemerle вроде бы и в чем то эффективней Lisp, но как это использовать — непонятно.


Тем кто не использует — конечно не понятно. А тем кто использует очень даже понятно. Мне нет нужды то и дело прибегать к помощи С. Все библиотеки я могу писать на там же языке, что и прикладной код.

A>И еще: известен ли вам проект, написанный на Lisp и переписанный на Nemerle, поработав с которым можно было бы сказать — "так, вот этот подонок тормозит, все срочно идем на Nemerle (Assembler, C, РЯП, нужное подчеркнуть)"?


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

А в истории примеры были. Тот же Яховский интернет-магазин который после Грэхэма был переписан то ли на плюсах, то ли еще на чем-то.

A>Есть ли математическое обоснование того, что Nemerle будет, например в 2-4 раза эффективнее для такого-то класса задач на таких-то машинах чем какая-либо популярная реализация Common Lisp (или что-то другое)?


Ага. Его система типов статическая. И есть не одна работа описывающая почему такие системы типов можно компилировать в эффективный машинный код.

В общем, Немерле это и есть качественный статически типизированный язык с сишным синтаксисом и макросистемой лиспа.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[9]: Amplifying C
От: VladD2 Российская Империя www.nemerle.org
Дата: 29.01.10 17:24
Оценка:
Здравствуйте, Mr.Cat, Вы писали:

MC>Ну это примерно то же самое, что и в syntax-case: по умолчанию создаваемые макросом символы не перекрываются ни с какими именами, а используемые ссылки относятся к области видимости в месте объявления макроса. По необходимости это ломается, благодаря параметру у datum->syntax, указывающему, откуда для вводимого символа унаследовать "контекст".

MC>Вот классическая копипаста из r6rs (макрос создает внутри блока кода неявный биндинг):
MC>
MC>;(define-syntax loop
MC>;  (lambda (x)
MC>;    (syntax-case x ()
MC>;      [(k e ...)
MC>;       (with-syntax
MC>;          ([break (datum->syntax #’k ’break)]) ;Прошу прощения за вставленный форматтером коммент после стрелки, там его быть не должно
MC>;          #’(call-with-current-continuation
MC>;              (lambda (break)
MC>;                (let f () e ... (f)))))])))
MC>;


Ну, и тебе эта каша нравится?

MC>В данном случае, кстати, видно, что цитирование в немерле — это аналог не лиспового цитирования, а создания синтаксических объектов в схемском syntax-case: syntax-quote (ака #'), datum->syntax и т.п.


В немерле цитирование не из CL или Схемы, а "под влиянием". Там еще 2-3 системы рассматривалось. Схема одна из них. Из нее как раз взята идея гигиены. Кроме того много взять из Темлэйт Хаскель. Более подробно об этом можно прочесть в переводе статьи автора макросистемы — Камила Скальски:
http://rsdn.ru/article/nemerle/nemerleMacros.xml
Автор(ы): Kamil Skalski, Michal Moskal и Pawel Olszta
Дата: 23.05.2006
Пример C++ показывает, что индустрии нужны системы метапрограммирования – даже достаточно причудливая система шаблонов широко используется для вычислений во время компиляции. Эта статья является исследованием возможного внедрения техники метапрограммирования в индустриальную среду в более чистой форме. Мы, таким образом, фокусируемся на том, чтобы сделать нашу систему легкой в использовании для программистов, как пишущих, так и использующих макросы.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[10]: Amplifying C
От: Mr.Cat  
Дата: 29.01.10 17:33
Оценка:
Здравствуйте, VladD2, Вы писали:
MC>>Вот классическая копипаста из r6rs (макрос создает внутри блока кода неявный биндинг):
MC>>
MC>;>(define-syntax loop
MC>;>  (lambda (x)
MC>;>    (syntax-case x ()
MC>;>      [(k e ...)
MC>;>       (with-syntax
MC>;>          ([break (datum->syntax #’k ’break)]) ;Прошу прощения за вставленный форматтером коммент после стрелки, там его быть не должно
MC>;>          #’(call-with-current-continuation
MC>;>              (lambda (break)
MC>;>                (let f () e ... (f)))))])))
MC>;>

VD>Ну, и тебе эта каша нравится?
А что не так? Это просто копипаста из доки. 4 строчки от дефайна до паттерна в той plt можно сократить в одну define-syntax-rule (см. мой пост про #%app), with — это типичный стиль введения биндинга, ну а дальше уж собственно тело пошло. В конце концов, если что-то хочется сократить и знаешь как — можно и макрос написать.
Re[7]: Amplifying C
От: VladD2 Российская Империя www.nemerle.org
Дата: 29.01.10 17:38
Оценка:
Здравствуйте, yumi, Вы писали:

Y>Жаль. Как раз, один мой проект, кастомер просит перевести под Моно. Значит не судьба, ну это и к лучшему, перепишу на Питоне, так будет гораздо быстрее.


Под Моно не собирается сам компилятор. Но уже собранный компилятор использовать можно. И, естественно, собранные под дотнетом сборки так же работают под Моно.

В общем, попробуй просто взять компилятор из бута:

Y>Моно, это не только Линукс, это "Линукс в том числе".


Без разницы. Интеграция работает только под дотнетом.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[14]: Amplifying C
От: VladD2 Российская Империя www.nemerle.org
Дата: 29.01.10 17:54
Оценка:
Здравствуйте, Mr.Cat, Вы писали:

MC>Ага, т.е. в немерле можно прямо посреди текста программы писать код на произвольном, определенном разработчиком языке, типа

MC>
MC>basic(
MC>  10 SIN
MC>  20 GOTO HELL)
MC>


Не все так просто, но в принципе этого можно достичь.

MC>Соответственно, возникают вопросы:

MC>1. Как в случае компрехеншена компилятор понимает, каким макросом его обрабатывать?
MC>2. Как компилятор понимает, что внутри использования некоего макроса нужно переключиться на другую грамматику (а потом и переключиться обратно)? Он ведь в процессе разбора текста должен как-то понять, что basic — это использование макроса и переключиться на другую грамматику.

Если брать данный гипотетический пример, то basic будет рассматриваться как просто макрос (даже не поддерживающий синтаксис). Далее есть два варианта:
1. Макрос может получать код немерла (на который до типизации налагается очень мало ограничений).
2. Он может получать так называемый свернутый по скобкам список лексем.

Второй случай значительно сложнее в разборе, но зато налагает совсем мало ограничений. Главное из них — это парность скобок (все открывающие скобки всех типов должны иметь соответствующее количество закрывающих скобок того же типа). Это нечто похожее на S-выражения лиспа, но с несколько более сложной структурой. Так вот этот список лексем можно интерпретировать как угодно. Например, переписав его в код который будет реализовывать семантику Бэйсика.

VD>>Так что никаких принципиальных проблем нет. И при этом нет нужды жить в спартанских условиях (писать код без синтаксиса).

MC>Это не спартанские условия. Просто некоторые тут страдают скобкофобией разной степени тяжести.

Дело не с кобках. Дело именно в отсутствии синтаксиса и ужасных решениях вроде знаков #' для получения ссылки на функцию.
В реальных условиях все же макросы пишутся не так часто. А писать обычный код лучше все же на языке у которого есть хорошо читаемый синтаксис.

В общем, в Лиспе мне нравится только макросы. Точнее даже сама идея языковой расширяемости. Это действительно "офигительно мега круто" (с). А вот все остальное в нем очень сильно устарело или изначально не удобно.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[11]: Amplifying C
От: VladD2 Российская Империя www.nemerle.org
Дата: 29.01.10 18:00
Оценка:
Здравствуйте, Mr.Cat, Вы писали:

MC>Здравствуйте, VladD2, Вы писали:

MC>>>Вот классическая копипаста из r6rs (макрос создает внутри блока кода неявный биндинг):
MC>>>
MC>;>>(define-syntax loop
MC>;>>  (lambda (x)
MC>;>>    (syntax-case x ()
MC>;>>      [(k e ...)
MC>;>>       (with-syntax
MC>;>>          ([break (datum->syntax #’k ’break)]) ;Прошу прощения за вставленный форматтером коммент после стрелки, там его быть не должно
MC>;>>          #’(call-with-current-continuation
MC>;>>              (lambda (break)
MC>;>>                (let f () e ... (f)))))])))
MC>;>>

VD>>Ну, и тебе эта каша нравится?
MC>А что не так?

Каша. Это единственное слово которое приходит на ум.
Туча малопонятных и совершенно не нужных приседаний.

MC>Это просто копипаста из доки. 4 строчки от дефайна до паттерна в той plt можно сократить в одну define-syntax-rule (см. мой пост про #%app), with — это типичный стиль введения биндинга, ну а дальше уж собственно тело пошло. В конце концов, если что-то хочется сократить и знаешь как — можно и макрос написать.


Ну, так надо было изначально написать, а не вываливать на людей какие-то кишки реализации. В таком виде — это ужасная каша в народе именуемая быдлокодом.
И почему-то скобки и другие коды как данные не помогают сделать код прозрачным и простым для понимания.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[15]: Amplifying C
От: Mr.Cat  
Дата: 29.01.10 18:01
Оценка:
Здравствуйте, VladD2, Вы писали:
MC>>Соответственно, возникают вопросы:
MC>>1. Как в случае компрехеншена компилятор понимает, каким макросом его обрабатывать?
MC>>2. Как компилятор понимает, что внутри использования некоего макроса нужно переключиться на другую грамматику (а потом и переключиться обратно)? Он ведь в процессе разбора текста должен как-то понять, что basic — это использование макроса и переключиться на другую грамматику.

Ок, в целом понятно.
А как насчет компрехеншена? Он же какой-то безымянный получается? Как компилятор понимает, что надо вызвать определенный макрос?
Re[16]: Amplifying C
От: VladD2 Российская Империя www.nemerle.org
Дата: 29.01.10 18:32
Оценка: 5 (1)
Здравствуйте, Mr.Cat, Вы писали:

MC>Ок, в целом понятно.

MC>А как насчет компрехеншена? Он же какой-то безымянный получается? Как компилятор понимает, что надо вызвать определенный макрос?

С компрешеншеном именем макроса является $. На самом деле "$", если честно, очень перегруженный символ в немерле, и из-за этого его компилятор специальным образом обрабатывает. Но нет особых проблем создать макрос с именем $$, @ или вообще Ѡ (ведь поддерживается Юникод).

В общем, единственная проблема — это выделить для компилятора то места откуда начинается новый синтаксис.

У текущей версии немерла все же ограничения есть. Плюс не все можно сделать просто. Скажем парсинг EBNF-грамматики — это вот такой вот файлик:
http://nemerle.googlecode.com/svn/nemerle/trunk/snippets/peg-parser/LRPEGCC/Parsing.n

Но в скором времени мы хотим стартовать новую версию немерла (2.0) в которой парсер будет расширяться практически без ограничений. И единственным требованием на расширение грамматики будет совместимость расширения с тем контекстом из которого она используется. Не будет нужны делать какие-то там префиксы как это требуется сейчас. Отпадет требование сворачивания по скобкам. Более того можно будет даже парсить языки вроде Фортнана (где распознавание токенов ведется по уникальным правилам), так как в нем не будет отдельного лексера, а макросы смогут просто задавать полностью собственную грамматику.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[12]: Amplifying C
От: Mr.Cat  
Дата: 29.01.10 18:47
Оценка:
Здравствуйте, VladD2, Вы писали:
VD>Туча малопонятных и совершенно не нужных приседаний.
Ну там не приседания, а голая правда о syntax-case. Что, например, непонятно?

VD>Ну, так надо было изначально написать

Ну, например, можно устроить себе вот такой синтаксис:
(syntax-case-rule (loop body ...)
 (with-bound #'loop (break)
   #'(call-with-current-continuation
      (lambda (break)
        (let f () body ... (f))))))

С помощью примерно таких макросов (про define-syntax-rule я тебя немного обманул, он в syntax-rules разворачивается, а не в syntax-case):
(define-syntax with-bound
  (syntax-rules ()
    ((_ ctx (id ...) e)
     (with-syntax ((id (datum->;syntax ctx (quote id))) ...) ;Тут  форматтер снова вставит ; после ->
       e))))

(define-syntax syntax-case-rule
  (syntax-rules ()
    ((_ (id . pattern) template)
     (define-syntax id
       (lambda (x)
         (syntax-case x ()
           ((id . pattern) template)))))))
Re[17]: Amplifying C
От: Mr.Cat  
Дата: 29.01.10 18:48
Оценка:
Здравствуйте, VladD2, Вы писали:
VD>В общем, единственная проблема — это выделить для компилятора то места откуда начинается новый синтаксис.
Вот это мне и не было понятно в случае немерле. Теперь понятнее.
Re[10]: Amplifying C
От: A13x США  
Дата: 01.02.10 13:08
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, A13x, Вы писали:


A>...


VD>О! Супер. Великое достижение человечества. Функция инкремента быал скомпилирована в 4 маш-инструкции. Для сравнения берем аналогичный код на Немерле:

VD>
VD>module Program
VD>{
VD>  Inc(x : int) : int { x + 1 }
  
VD>  Main() : void
VD>  {
VD>    WriteLine(Inc(5));
VD>  }
VD>}
VD>

VD>Смотрим результат в функции Main:
VD>
VD>0000000b  mov         ecx,6 
VD>00000010  call        FFFFFFFFEF5EDD40 
VD>

VD>Надеюсь ясно почему код приходится смотреть в функции Main?

Ясно, но при таком подходе такой же результат достижим и в Lisp:


* (declaim (optimize speed (safety 0) (space 0) (debug 0)))

* (defun foo () (flet ((f (x) (+ x 100))) (print (f 10))))

FOO
* (foo)

110
110
* (compile 'foo)

FOO
NIL
NIL
* (disassemble 'foo)

; disassembly for FOO
; 23B6C59A:       BAB8010000       MOV EDX, 440

;       9F:       8B0570C5B623     MOV EAX, [#x23B6C570]  ; #<FDEFINITION object for PRINT>
;       A5:       B904000000       MOV ECX, 4
;       AA:       FF7504           PUSH DWORD PTR [EBP+4]
;       AD:       FF6005           JMP DWORD PTR [EAX+5]
NIL


В Lisp функции можно переопределять, хотя бы из того же REPL-а, таким образом встроить глобальную функцию не получится (но, если я не ошибаюсь, есть какой то способ, package lock или что-то вроде).

По поводу остального — "будем посмотреть"
Re[11]: Amplifying C
От: VladD2 Российская Империя www.nemerle.org
Дата: 01.02.10 20:09
Оценка:
Здравствуйте, A13x, Вы писали:

A>
A>* (defun foo () (flet ((f (x) (+ x 100))) (print (f 10))))
A>; disassembly for FOO
A>; 23B6C59A:       BAB8010000       MOV EDX, 440

A>;       9F:       8B0570C5B623     MOV EAX, [#x23B6C570]  ; #<FDEFINITION object for PRINT>
A>;       A5:       B904000000       MOV ECX, 4
A>;       AA:       FF7504           PUSH DWORD PTR [EBP+4]
A>;       AD:       FF6005           JMP DWORD PTR [EAX+5]
A>NIL
A>


Что-то у меня сегодня с математикой проблемы. Я правильно понял, что 10 + 100 = 440?

И еще, какова здесь роль flet?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[12]: Amplifying C
От: A13x США  
Дата: 02.02.10 13:55
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, A13x, Вы писали:


A>>
A>>* (defun foo () (flet ((f (x) (+ x 100))) (print (f 10))))
A>>; disassembly for FOO
A>>; 23B6C59A:       BAB8010000       MOV EDX, 440

A>>;       9F:       8B0570C5B623     MOV EAX, [#x23B6C570]  ; #<FDEFINITION object for PRINT>
A>>;       A5:       B904000000       MOV ECX, 4
A>>;       AA:       FF7504           PUSH DWORD PTR [EBP+4]
A>>;       AD:       FF6005           JMP DWORD PTR [EAX+5]
A>>NIL
A>>


VD>Что-то у меня сегодня с математикой проблемы. Я правильно понял, что 10 + 100 = 440?


Не знаю настолько подробно, однако, похоже, дело в каком-то внутреннем представлении числа, или, может 440 — это 110 + метаинформация о типе fixnum в битах?
К примеру, для 3-х будет тоже непонятное значение — MOV EDX, 12.


VD>И еще, какова здесь роль flet?


определяет локальную функцию. Поскольку, очевидно, компилятору известно, что эта функция не может быть переопределена пользователем (например в REPL), компилятор подставляет вычисленное значение вместо вызова функции.
Re[13]: Amplifying C
От: VladD2 Российская Империя www.nemerle.org
Дата: 02.02.10 16:46
Оценка:
Здравствуйте, A13x, Вы писали:

A>Не знаю настолько подробно, однако, похоже, дело в каком-то внутреннем представлении числа, или, может 440 — это 110 + метаинформация о типе fixnum в битах?

A>К примеру, для 3-х будет тоже непонятное значение — MOV EDX, 12.

Ясно. Химичат, значит.

VD>>И еще, какова здесь роль flet?


A>определяет локальную функцию. Поскольку, очевидно, компилятору известно, что эта функция не может быть переопределена пользователем (например в REPL), компилятор подставляет вычисленное значение вместо вызова функции.


Дык в моем примере функция была совершенно обычная. Не побоюсь, даже, этого слова — метод . Причем функция может быть и из другого модуля. 3.5 фрэймворк проводит инлайнинг между сборками.

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

Дотнет и ява тем и хороши, что снимают с реализатора компилятора эти проблемы.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: Amplifying C
От: vdimas Россия  
Дата: 02.02.10 23:42
Оценка: -1
Здравствуйте, VladD2, Вы писали:

VD>Тем не менее сам подход — использование макросов времени компиляции — очень даже жизнеспособный, и уехать на нем можно очень даже далеко.


Только если сам процесс компиляции молниеносный, как в Лисп.
Re[16]: Amplifying C
От: VladD2 Российская Империя www.nemerle.org
Дата: 03.02.10 19:42
Оценка: 4 (1)
Здравствуйте, Mr.Cat, Вы писали:

MC>Ок, в целом понятно.

MC>А как насчет компрехеншена? Он же какой-то безымянный получается? Как компилятор понимает, что надо вызвать определенный макрос?

Вот, кстати, еще один пример DSL-я на немерле нарисовался сегодня — DSL описывающий конечный автомат:
Описание проблемы
Автор: CodingUnit
Дата: 03.02.10

Реализация макроса разбирающего DSL (без генерации кода самого конечного автомата).
Автор: VladD2
Дата: 03.02.10


Там приведен рабочий код макры. Если чтение немерла для тебя не является огромной проблемой, то можешь понять как это работает (приемы проектирования и реализации).

Думаю так будет понятнее, чем абстрактные описания.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[9]: Amplifying C
От: Mr.Cat  
Дата: 08.02.10 23:02
Оценка:
Здравствуйте, A13x, Вы писали:
A>elisp не компилирует в машинный код (во всяком случае точно не в emacs), какие-то базовые части, понятно, надо было реализовывать на С. Не забываем, что emacs был написан довольно давно и требования по памяти и ресурсам были не в пример жестче чем сейчас.
A>На современном оборудовании абсолютно никаких тормозов я не замечал (средненький ноутбук — DELL двухгодовой давности), чего не сказать про 2008 студию даже со всеми отключенными плагинами на значительно более мощной машине.

Кстати, насчет того, как "не тормозит" емакс. Сейчас сижу пишу текст в emacs23+auctex — так вот плавно текст невозможно (часто, чтобы перемещаться по строчками, я зажимаю "вверх" или "вниз" или скроллю тачпадом) — скроллится рывками и при этом "раскручивает" процессор. Жутко бесит.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.