Как написать виртуальную машину на LISP
От: Turtle.BAZON.Group  
Дата: 09.08.09 18:45
Оценка: 29 (5)
HOWTO по написанию виртуальной машины на Common Lisp по спецификации из ICFPC-2009
Re: Как написать виртуальную машину на LISP
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 10.08.09 06:09
Оценка:
Спасибо! Теперь я точно не стану использовать лисп на таких задачах.
Re[2]: Как написать виртуальную машину на LISP
От: Turtle.BAZON.Group  
Дата: 10.08.09 09:14
Оценка:
Здравствуйте, D. Mon, Вы писали:

А аргументированный ответ, мы, наверное, увидим после обеда?

DM>Спасибо! Теперь я точно не стану использовать лисп на таких задачах.
Re[2]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 10.08.09 10:39
Оценка:
Здравствуйте, D. Mon, Вы писали:

DM>Спасибо! Теперь я точно не стану использовать лисп на таких задачах.


А зря. На Лиспе, например, очень легко можно написать эффективный компилятор для любой ВМ, используя одни только макры. На языке без макр это будет очень и очень сложной задачей, или придётся ограничиваться тормозным интерпретатором.
Re[3]: Как написать виртуальную машину на LISP
От: Mr.Cat  
Дата: 10.08.09 10:49
Оценка:
Здравствуйте, Аноним, Вы писали:
А> А зря. На Лиспе, например, очень легко можно написать эффективный компилятор для любой ВМ, используя одни только макры. На языке без макр это будет очень и очень сложной задачей, или придётся ограничиваться тормозным интерпретатором.
Тут скорее дело не в макросах, а в возможностях кодогенерации как таковой.
Re[4]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 10.08.09 11:13
Оценка:
Здравствуйте, Mr.Cat, Вы писали:

MC>Тут скорее дело не в макросах, а в возможностях кодогенерации как таковой.


Такая возможность есть почти везде (ну кроме разве что айфона). Просто одно дело генерить напрямую биткод LLVM или там например JVM через BCEL — это сложно и потенциально взрывоопасно, и совсем другое дело использовать для кодогенерации метапрограммирование — это прозрачно, тривиально, и возможностей ошибиться на этом пути гораздо меньше.
Re[5]: Как написать виртуальную машину на LISP
От: Mr.Cat  
Дата: 10.08.09 11:39
Оценка:
Здравствуйте, Аноним, Вы писали:
А> Такая возможность есть почти везде (ну кроме разве что айфона). Просто одно дело генерить напрямую биткод LLVM или там например JVM через BCEL — это сложно и потенциально взрывоопасно, и совсем другое дело использовать для кодогенерации метапрограммирование — это прозрачно, тривиально, и возможностей ошибиться на этом пути гораздо меньше.

Ну например рантайм .net включает в себя компилятор c#. Т.е. часто можно просто генерить код в виде текста.
Конечно, приятнее генерить не текст, а ast. В дотнете, например, есть вроде codedom И dlr для этого (хотя я не работал с ними). Так что все, ИМХО, упирается в удобство инструментов.
Re[6]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 10.08.09 11:55
Оценка:
Здравствуйте, Mr.Cat, Вы писали:

MC>Ну например рантайм .net включает в себя компилятор c#.


С каких это пор? У них нет ещё managed компилятора, они о нём только мечтают. С Mono это ещё возможно в принципе, а в родном .NET — фигушки.

MC> Т.е. часто можно просто генерить код в виде текста.


Можно. Это тоже своего рода метапрограммирование. Но оно намного хуже того, что есть в Лиспах и прочих Немерлах, в силу сугубой однопроходности. Преобразование от виртуальной машины, от AST какого либо экзотического DSL, от комманд хитрого агентного протокола, и т.п., необходимо непременно делать в один шаг. При малейшей нетривиальности языка это становится крайне сложной и потенциально ошибкоёмкой задачей. Тогда как с метапрограммированием на макрах преобразование из DSL в целевой язык может идти во много этапов, через промежуточные языки, и каждое такое преобразование формулируется единообразно, в виде набора макр.

MC>Конечно, приятнее генерить не текст, а ast. В дотнете, например, есть вроде codedom И dlr для этого (хотя я не работал с ними). Так что все, ИМХО, упирается в удобство инструментов.


Не только "удобство", но и вообще адекватность. Инструмент, требующий чрезмерно сложной кодогенерации, приводит к серьёзным ошибкам, неизбежно. Я уж не говорю о стоимости разработки с неадекватным инструментом.
Re[7]: Как написать виртуальную машину на LISP
От: Mr.Cat  
Дата: 10.08.09 12:27
Оценка:
Здравствуйте, Аноним, Вы писали:
MC>>Ну например рантайм .net включает в себя компилятор c#.
А> С каких это пор? У них нет ещё managed компилятора, они о нём только мечтают. С Mono это ещё возможно в принципе, а в родном .NET — фигушки.
А при чем тут managed-компилятор? Виндоз\Microsoft.NET\Framework\Версия\csc.exe.

С остальным спорить не стану.
Re[8]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 10.08.09 12:40
Оценка:
Здравствуйте, Mr.Cat, Вы писали:

MC>А при чем тут managed-компилятор? Виндоз\Microsoft.NET\Framework\Версия\csc.exe.


Ну и какая это на фиг часть рантайма? На ASP.NET хостинге за него не подёргаешь. На пользовательском компьютере с голым framework, без SDK — тем более. С тем же успехом можно и на наличие gcc на пользовательской машине рассчитывать.

Правда, всегда можно таскать компилятор от Mono в виде dll, если уж так хочется генерить код именно на C# (не вижу, однако, никаких причин, почему такие странные желания могли бы у кого либо возникнуть).
Re[9]: Как написать виртуальную машину на LISP
От: samius Япония http://sams-tricks.blogspot.com
Дата: 10.08.09 12:53
Оценка:
Здравствуйте, Аноним, Вы писали:

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


MC>>А при чем тут managed-компилятор? Виндоз\Microsoft.NET\Framework\Версия\csc.exe.


А> Ну и какая это на фиг часть рантайма? На ASP.NET хостинге за него не подёргаешь. На пользовательском компьютере с голым framework, без SDK — тем более. С тем же успехом можно и на наличие gcc на пользовательской машине рассчитывать.


http://msdn.microsoft.com/en-us/library/microsoft.csharp.csharpcodeprovider.aspx
Assembly: System (in System.dll)

Я полагаю, что на наличие System.dll можно рассчитывать.

а csc.exe — не совсем компилятор. Это его command-line оболочка, на сколько мне известно.
Re[9]: Как написать виртуальную машину на LISP
От: Mr.Cat  
Дата: 10.08.09 13:22
Оценка:
Здравствуйте, Аноним, Вы писали:
А> Ну и какая это на фиг часть рантайма? На ASP.NET хостинге за него не подёргаешь. На пользовательском компьютере с голым framework, без SDK — тем более. С тем же успехом можно и на наличие gcc на пользовательской машине рассчитывать.
Это как раз в голом FW без sdk. Как он дружит с asp (в плане наличия привилегий на запуск) — хз.
Re[10]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 10.08.09 13:22
Оценка:
Здравствуйте, samius, Вы писали:

S>http://msdn.microsoft.com/en-us/library/microsoft.csharp.csharpcodeprovider.aspx

S>Assembly: System (in System.dll)

Он вызывает csc.exe

S>Я полагаю, что на наличие System.dll можно рассчитывать.


А вот на работоспособность CSharpCodeProvider без SDK — нельзя. Он исключение кинет, что мол "csc.exe не найден".

S>а csc.exe — не совсем компилятор. Это его command-line оболочка, на сколько мне известно.


Сам компилятор полностью unmanaged.

И частью framework-а не является.
Re[11]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 10.08.09 13:28
Оценка:
Здравствуйте, Аноним, Вы писали:

А> И частью framework-а не является.


Ха. А я таки облажался. Он всё же идёт с framework. А с ASP.NET не работает как раз таки благодаря ограничениям на security.

Но в любом случае — решение неюзабельное, важно, что не работает, а не почему оно не работает.
Re[11]: Как написать виртуальную машину на LISP
От: samius Япония http://sams-tricks.blogspot.com
Дата: 10.08.09 13:38
Оценка:
Здравствуйте, Аноним, Вы писали:

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


S>>http://msdn.microsoft.com/en-us/library/microsoft.csharp.csharpcodeprovider.aspx

S>>Assembly: System (in System.dll)

А> Он вызывает csc.exe


S>>Я полагаю, что на наличие System.dll можно рассчитывать.


А> А вот на работоспособность CSharpCodeProvider без SDK — нельзя. Он исключение кинет, что мол "csc.exe не найден".

Честно, говоря, не пробовал удалять csc.exe

S>>а csc.exe — не совсем компилятор. Это его command-line оболочка, на сколько мне известно.


А> Сам компилятор полностью unmanaged.

Да, известный факт. Ну и что что unmanaged.

А> И частью framework-а не является.

Является.
Не уверен, является ли он частью .NET Framework Client Profile.
Re[12]: Как написать виртуальную машину на LISP
От: samius Япония http://sams-tricks.blogspot.com
Дата: 10.08.09 13:39
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, Аноним, Вы писали:


А>> И частью framework-а не является.


А> Ха. А я таки облажался. Он всё же идёт с framework. А с ASP.NET не работает как раз таки благодаря ограничениям на security.


А> Но в любом случае — решение неюзабельное, важно, что не работает, а не почему оно не работает.

Почему же, очень даже юзабельное. Область приложения framework несколько шире, чем ASP.NET.
Re: Как написать виртуальную машину на LISP
От: frontsquat  
Дата: 10.08.09 13:44
Оценка:
Здравствуйте, Turtle.BAZON.Group, Вы писали:

TBG>HOWTO по написанию виртуальной машины на Common Lisp по спецификации из ICFPC-2009


А ссылка рабочая? Сейчас что-то нет.
Re[13]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 10.08.09 13:50
Оценка:
Здравствуйте, samius, Вы писали:

А>> Но в любом случае — решение неюзабельное, важно, что не работает, а не почему оно не работает.

S>Почему же, очень даже юзабельное. Область приложения framework несколько шире, чем ASP.NET.

Ага, вот поюзает его кто-то, от широты души, а потом мне его код из ASP.NET дёргать.

Не, я предпочитаю простые и надёжные методы — System.Reflection.Emit и Лисп с макрами поверх него.
Re[14]: Как написать виртуальную машину на LISP
От: Mr.Cat  
Дата: 10.08.09 14:01
Оценка: 1 (1)
Здравствуйте, Аноним, Вы писали:
А> Не, я предпочитаю простые и надёжные методы — System.Reflection.Emit и Лисп с макрами поверх него.
Какую имплементацию лиспа используешь для дотнета?

К слову о dsl на макрах. Чем дальше семантика dsl от семантики самого лиспа — тем ближе набор макров будет к традиционному компилятору. Так что я немного не разделяю лисподиферамбов в этой ветке.
Re[9]: Как написать виртуальную машину на LISP
От: cadet354 Россия
Дата: 10.08.09 14:05
Оценка:
Здравствуйте, <Аноним>, Вы писали:


А> Правда, всегда можно таскать компилятор от Mono в виде dll, если уж так хочется генерить код именно на C# (не вижу, однако, никаких причин, почему такие странные желания могли бы у кого либо возникнуть).

попробуй Linqpad, станет понятно зачем это надо.
... << RSDN@Home 1.2.0 alpha 4 rev. 1231>>
Re[15]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 10.08.09 14:10
Оценка:
Здравствуйте, Mr.Cat, Вы писали:

А>> Не, я предпочитаю простые и надёжные методы — System.Reflection.Emit и Лисп с макрами поверх него.

MC>Какую имплементацию лиспа используешь для дотнета?

Свою собственную, специально для кодогенерации писанную.

MC>К слову о dsl на макрах. Чем дальше семантика dsl от семантики самого лиспа — тем ближе набор макров будет к традиционному компилятору.


Это не совсем и не всегда так. Можно очень далеко уйти от Лиспа (то есть, от eager application, и т.п.) инкрементально добавляя макры. А чем больше языковых фичей (в том числе и с очень другой семантикой), тем проще делать каждую новую фичу, просто преобразуя её к комбинации существующих. А если и целевых языков более одного, например, кроме Лиспа можно (пользуясь теми же S-выражениями) и более низкоуровневые языки описывать — то вообще любой язык можно из одних только макр сделать.

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

Ну а на случай, когда простыми макрами всё же сложно пользоваться — тут можно и специальный язык для описания и AST, и преобразований сделать. Как вот здесь, например:

http://www.meta-alternative.net/calc.pdf (отсюда: http://lambda-the-ultimate.org/node/2895)

Можно и ещё проще сделать, и мощнее — Лисп бесконечно гибкий.
Re[10]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 10.08.09 14:15
Оценка:
Здравствуйте, cadet354, Вы писали:

А>> Правда, всегда можно таскать компилятор от Mono в виде dll, если уж так хочется генерить код именно на C# (не вижу, однако, никаких причин, почему такие странные желания могли бы у кого либо возникнуть).

C>попробуй Linqpad, станет понятно зачем это надо.

Посмотрел. Всё равно не понял. Это же всё ещё C#. Далеко не лучший скриптовый язык. Linq хорош, но вокруг всё тот же тяжеловесный C# остаётся.
Re[3]: Как написать виртуальную машину на LISP
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 10.08.09 14:19
Оценка: +1
Здравствуйте, Turtle.BAZON.Group, Вы писали:

DM>>Спасибо! Теперь я точно не стану использовать лисп на таких задачах.

TBG>А аргументированный ответ, мы, наверное, увидим после обеда?

Что ж, обед прошел, аргументы простые: по сравнению с моим решением на Окамле тут кода сильно больше, а скорость на порядок ниже. Подозреваю, что скорость можно улучшить, но тогда код еще втрое больше станет.
Re[3]: Как написать виртуальную машину на LISP
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 10.08.09 14:27
Оценка:
Здравствуйте, Аноним, Вы писали:

DM>>Спасибо! Теперь я точно не стану использовать лисп на таких задачах.


А> А зря. На Лиспе, например, очень легко можно написать эффективный компилятор для любой ВМ, используя одни только макры. На языке без макр это будет очень и очень сложной задачей, или придётся ограничиваться тормозным интерпретатором.


Пока это лишь слова. На деле придется выбирать: или "очень легко", или "эффективный". В примере топикстартера не похоже, что компиляция/кодогенерация вообще имела место — ускорение получилось как при простой замене инструкций на выполняющие их лямбды. А итоговая скорость в 4-5 раз ниже "тормозного интерпретатора" на языке со статической типизацией. Т.е. пока что я вижу контрпример — "ВМ на лиспе писать можно, но получается медленно и громоздко".
Re[11]: Как написать виртуальную машину на LISP
От: cadet354 Россия
Дата: 10.08.09 14:28
Оценка:
Здравствуйте, <Аноним>, Вы писали:

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


А>>> Правда, всегда можно таскать компилятор от Mono в виде dll, если уж так хочется генерить код именно на C# (не вижу, однако, никаких причин, почему такие странные желания могли бы у кого либо возникнуть).

C>>попробуй Linqpad, станет понятно зачем это надо.

А> Посмотрел. Всё равно не понял. Это же всё ещё C#. Далеко не лучший скриптовый язык. Linq хорош, но вокруг всё тот же тяжеловесный C# остаётся.

ты не понял, так кроме линка можно писать код, на обычном C#.
... << RSDN@Home 1.2.0 alpha 4 rev. 1231>>
Re[4]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 10.08.09 14:32
Оценка:
Здравствуйте, D. Mon, Вы писали:

А>> А зря. На Лиспе, например, очень легко можно написать эффективный компилятор для любой ВМ, используя одни только макры. На языке без макр это будет очень и очень сложной задачей, или придётся ограничиваться тормозным интерпретатором.


DM>Пока это лишь слова.


Это практический опыт.

DM> На деле придется выбирать: или "очень легко", или "эффективный".


Прелесть Лиспа как раз в том и заключается, что выбирать не надо. За эффективность компилятор Лиспа отвечает — его много лет много людей писали. Зачем их труд повторять? Мы просто преобразуем код VM в код на Лиспе. Макрами. Проще уж и вовсе некуда. Такой компилятор намного проще любого интерпретатора.

DM> В примере топикстартера не похоже, что компиляция/кодогенерация вообще имела место


К сожалению, я не имел возможности посмотреть на его пример — ссылка не работает.

DM> — ускорение получилось как при простой замене инструкций на выполняющие их лямбды. А итоговая скорость в 4-5 раз ниже "тормозного интерпретатора" на языке со статической типизацией.


Это претензии к конкретной реализации. Если там просто интерпретатор — тогда это не интересно. Это не lisp way.

DM> Т.е. пока что я вижу контрпример — "ВМ на лиспе писать можно, но получается медленно и громоздко".


Можно в разы быстрее, чем на OCaml. Разве что у MetaOCaml появится native backend — тогда только и будет смысл с Лиспом в эффективности тягаться.
Re[12]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 10.08.09 14:37
Оценка:
Здравствуйте, cadet354, Вы писали:

А>> Посмотрел. Всё равно не понял. Это же всё ещё C#. Далеко не лучший скриптовый язык. Linq хорош, но вокруг всё тот же тяжеловесный C# остаётся.

C>ты не понял, так кроме линка можно писать код, на обычном C#.

Именно это я и понял. Я не понимаю, кто может захотеть писать код на обычном C#. Он тяжеловесен. Не для коротких кусочков скриптового кода. И уж тем более не для кодогенерации из какого либо другого языка. Опять же в силу тяжеловесности.
Re[4]: Как написать виртуальную машину на LISP
От: Mr.Cat  
Дата: 10.08.09 15:06
Оценка:
Здравствуйте, D. Mon, Вы писали:
DM>Пока это лишь слова. На деле придется выбирать: или "очень легко", или "эффективный".
Соглашусь. При использовании макросов целевой язык будет лиспом, т.е. при реализации сабжевой vm таким образом мы получим преобразование:
низкоуровневый язык -макросы-> высокоуровневый язык -имплементация лиспа-> низкоуровневый язык.
Вполне очевидно, что среднее звено часто стоит исключить.

Хотя для высокоуровневых dsl макросы часто хороши.
Вообще, мне кажется, что имплементация некоего языка (vm) должна по возможности выполняться на языке более низкого уровня, а если ниже уж некуда — то на чем-то типа C.
Re[5]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 10.08.09 15:29
Оценка:
Здравствуйте, Mr.Cat, Вы писали:

MC>Вполне очевидно, что среднее звено часто стоит исключить.


Естественно. Потому и говорю, что очень полезно иметь в Лиспе встроенный низкоуровневый язык, чтоб он был целевым языком для таких преобразований. Например, был такой muLisp под MS DOS — там можно было вообще ассемблер встраивать.

MC>Вообще, мне кажется, что имплементация некоего языка (vm) должна по возможности выполняться на языке более низкого уровня, а если ниже уж некуда — то на чем-то типа C.


Язык самих макр не обязательно должен совпадать с целевым языком — и в этом вся сила Лиспа и есть. Я тут приводил уже примеры.
Re[6]: Как написать виртуальную машину на LISP
От: Mr.Cat  
Дата: 10.08.09 16:17
Оценка:
Здравствуйте, Аноним, Вы писали:
MC>>Вообще, мне кажется, что имплементация некоего языка (vm) должна по возможности выполняться на языке более низкого уровня, а если ниже уж некуда — то на чем-то типа C.
А> Язык самих макр не обязательно должен совпадать с целевым языком — и в этом вся сила Лиспа и есть. Я тут приводил уже примеры.
Кто ж спорит-то?
Я немного неточно выразился. Под "имплементация некоего языка" имел в виду "интерпретация на" или "компиляция в".
Re[5]: Как написать виртуальную машину на LISP
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 10.08.09 16:24
Оценка:
Здравствуйте, Аноним, Вы писали:

А> За эффективность компилятор Лиспа отвечает — его много лет много людей писали.


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

A>Зачем их труд повторять? Мы просто преобразуем код VM в код на Лиспе. Макрами. Проще уж и вовсе некуда. Такой компилятор намного проще любого интерпретатора.


Вроде, ТС так и сделал. Получилось плохо — не проще интерпретатора и не сильно быстрее (в полтора раза всего). Может быть SBCL плохой компилятор, а может автор где-то накосячил, я не знаю.
Re[6]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 10.08.09 16:29
Оценка:
Здравствуйте, D. Mon, Вы писали:

DM>Плохо писали, видимо.


Не очень уж и плохо. SBCL весьма шустрый.

DM>Вроде, ТС так и сделал.


Страница всё так же недоступна. Не могу посмотреть.

DM> Получилось плохо — не проще интерпретатора и не сильно быстрее (в полтора раза всего).


Не верю. Не может оно медленным получиться. Если там конечно не код из одних лямбд генерится.
Re[4]: Как написать виртуальную машину на LISP
От: MasterZiv СССР  
Дата: 10.08.09 16:31
Оценка:
Mr.Cat пишет:

> А> А зря. На Лиспе, например, очень легко можно написать эффективный

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

Безусловно. Но кодогенерация на (комон) лиспе доведена до совершенства,
почему бы её не использовать ? Код может генерировать код, который может
генерировать код, который может генерировать код ...

И так до бесконесности. И всё будет лисп. Почему бы и нет ?
Posted via RSDN NNTP Server 2.1 beta
Re[2]: Как написать виртуальную машину на LISP
От: Turtle.BAZON.Group  
Дата: 10.08.09 18:56
Оценка:
Здравствуйте, frontsquat, Вы писали:

F>А ссылка рабочая? Сейчас что-то нет.


Возникли проблемы с сетью. Ссылка временно нерабочая. Надеюсь, это быстро будет исправлено.
Re[5]: Как написать виртуальную машину на LISP
От: FR  
Дата: 11.08.09 04:49
Оценка:
Здравствуйте, Аноним, Вы писали:

А> Можно в разы быстрее, чем на OCaml. Разве что у MetaOCaml появится native backend — тогда только и будет смысл с Лиспом в эффективности тягаться.


Для подобных вещей и camlp4 достаточно.
Re[6]: Как написать виртуальную машину на LISP
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 11.08.09 06:16
Оценка:
Здравствуйте, FR, Вы писали:

FR>Для подобных вещей и camlp4 достаточно.


MetaOcaml все же по смыслу ближе к лиспу — на нем можно специализировать функции в рантайме, а camlp4 — это все же компайлтайм. В версии 3.11 у окамла появилась нативная подгрузка кода, поэтому теперь теоретически нативному MetaOcaml'у ничего не мешает быть. Но на практике я его не щупал, а без этого это тоже лишь слова.
Re[6]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 11.08.09 08:40
Оценка:
Здравствуйте, FR, Вы писали:

А>> Можно в разы быстрее, чем на OCaml. Разве что у MetaOCaml появится native backend — тогда только и будет смысл с Лиспом в эффективности тягаться.


FR>Для подобных вещей и camlp4 достаточно.


Достаточно, но неприменимо. Он однопроходный, что делает его столь же неудобным, как текстовая кодогенерация.
Re[7]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 11.08.09 08:46
Оценка:
Здравствуйте, D. Mon, Вы писали:

DM>MetaOcaml все же по смыслу ближе к лиспу — на нем можно специализировать функции в рантайме, а camlp4 — это все же компайлтайм.


Рантайм или время компиляции — без разницы. В Лиспе макры во время компиляции раскрываются, а не во время исполнения. Важно, что с MetaOCaml можно многоуровневые макры делать, а camlp4 должен породить валидный OCaml с первого же прохода.

DM> В версии 3.11 у окамла появилась нативная подгрузка кода, поэтому теперь теоретически нативному MetaOcaml'у ничего не мешает быть. Но на практике я его не щупал, а без этого это тоже лишь слова.


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

Так что если так хочется метапрограммирование, но в статически типизированном языке, то выбирать придётся между Template Haskell и Nemerle.
Re[6]: Как написать виртуальную машину на LISP
От: MasterZiv СССР  
Дата: 12.08.09 05:21
Оценка:
D. Mon пишет:

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

> лиспе пока нет, как я понимаю.

Зачем он в лиспе-то ?
Posted via RSDN NNTP Server 2.1 beta
Re[7]: Как написать виртуальную машину на LISP
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 12.08.09 05:43
Оценка:
Здравствуйте, MasterZiv, Вы писали:

MZ>Зачем он в лиспе-то ?


Чтобы пример из первого поста (уже доступен, кстати) работал не 30 секунд, а 3, и при этом не надо было раздувать код аннотациями типов. Вот зачем.
Re[8]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 12.08.09 08:31
Оценка: -1
Здравствуйте, D. Mon, Вы писали:

MZ>>Зачем он в лиспе-то ?


DM>Чтобы пример из первого поста (уже доступен, кстати) работал не 30 секунд, а 3, и при этом не надо было раздувать код аннотациями типов. Вот зачем.


Ну так вывод типов в Лиспе делается тривиально. А вот наоборот, отрубить его от OCaml уже нельзя. Из Лиспа можно сделать OCaml, или OCaml нельзя сделать эффективно Лисп. Следовательно, Лисп фундаментальнее.
Re[9]: Как написать виртуальную машину на LISP
От: thesz Россия http://thesz.livejournal.com
Дата: 12.08.09 09:27
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, D. Mon, Вы писали:


MZ>>>Зачем он в лиспе-то ?

DM>>Чтобы пример из первого поста (уже доступен, кстати) работал не 30 секунд, а 3, и при этом не надо было раздувать код аннотациями типов. Вот зачем.
А> Ну так вывод типов в Лиспе делается тривиально. А вот наоборот, отрубить его от OCaml уже нельзя. Из Лиспа можно сделать OCaml, или OCaml нельзя сделать эффективно Лисп.

Я бы предложил сравнение.

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

Тогда как примитивный ОКамл на Лиспе потребует гораздо больше работы.

К тому же зачем сравнивать уже устаревший ОКамл с мощным Лиспом.

Давайте сравним современный Хаскель.

Вот и реализация Схемы есть: http://halogen.note.amherst.edu/~jdtang/scheme_in_48/tutorial/overview.html

Надо упомянуть, что ML был написан на Лиспе (и это на нём сказалось, см. The Zinc experiment) и на Лиспе же был написан один из первых компиляторов Хаскеля: Yake.

А> Следовательно, Лисп фундаментальнее.


По-моему, это поспешный вывод.

И ещё. "Фундаментальней" не значит "удобней".
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[10]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 12.08.09 09:36
Оценка:
Здравствуйте, thesz, Вы писали:

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


Не надо "примитивный". Надо "эффективный". Интерпретатор то минимального Лиспа любой дурак за час напишет.

T>Тогда как примитивный ОКамл на Лиспе потребует гораздо больше работы.


Не гораздо. Два-три часа максимум. Конкретнее — чуть больше тысячи строк кода с комментариями выходит.

T>К тому же зачем сравнивать уже устаревший ОКамл с мощным Лиспом.


Лисп как бы малость куда более "устаревший" и древний.

T>Давайте сравним современный Хаскель.


Он слишком жирным стал в последнее время.

T>Вот и реализация Схемы есть: http://halogen.note.amherst.edu/~jdtang/scheme_in_48/tutorial/overview.html


Интерпретатор. Не интересно. Хотя, на Template Haskell теоретически и компилятор можно было бы сделать.

T>Надо упомянуть, что ML был написан на Лиспе (и это на нём сказалось, см. The Zinc experiment) и на Лиспе же был написан один из первых компиляторов Хаскеля: Yake.


Да и YHC на Схеме написан. И что?

А>> Следовательно, Лисп фундаментальнее.


T>По-моему, это поспешный вывод.


Ну почему же? Фундаментальность — понятие строгое.

T>И ещё. "Фундаментальней" не значит "удобней".


Поскольку Лисп легко включает в себя весь ML, плюс много чего ещё, а в ML есть только ML — то да, удобнее. Но я не говорю "безопаснее", кстати.
Re[9]: Как написать виртуальную машину на LISP
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 12.08.09 10:08
Оценка:
Здравствуйте, Аноним, Вы писали:

А> Ну так вывод типов в Лиспе делается тривиально.


А можно чуть подробнее идею? Т.е. вот задумал человек решить задачку на ICFPC, и вместо простой реализации ВМ, которая будет написана быстро, но работать медленно, ты предлагаешь ему самостоятельно реализовывать вывод типов? Там и без этого четыре лиспера набрали в два с половиной раза меньше очков, чем один окамлер.

А> А вот наоборот, отрубить его от OCaml уже нельзя.


1. Зачем здравомыслящему человеку его вдруг отрубать? 2. Динамическая типизация делается на окамле элементарно, для работы с sexp'ами библиотек тоже предостаточно.

A> Из Лиспа можно сделать OCaml, или OCaml нельзя сделать эффективно Лисп. Следовательно, Лисп фундаментальнее.


А Си еще фундаментальнее, не говоря о макроассемблере. Толку то.
Re[11]: Как написать виртуальную машину на LISP
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 12.08.09 10:10
Оценка:
Здравствуйте, Аноним, Вы писали:

T>>Тогда как примитивный ОКамл на Лиспе потребует гораздо больше работы.


А> Не гораздо. Два-три часа максимум. Конкретнее — чуть больше тысячи строк кода с комментариями выходит.


Мне, как и многим присутствующим, было бы очень интересно об этом почитать поподробнее. Можно ссылку или описание какое-нибудь?
Re[10]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 12.08.09 10:56
Оценка:
Здравствуйте, D. Mon, Вы писали:

DM> Т.е. вот задумал человек решить задачку на ICFPC, и вместо простой реализации ВМ, которая будет написана быстро, но работать медленно, ты предлагаешь ему самостоятельно реализовывать вывод типов?


У любого прожженого лиспера таких реализаций готовеньких уже пара-тройка валяется в загашнике.

DM> Там и без этого четыре лиспера набрали в два с половиной раза меньше очков, чем один окамлер.


Там вообще лисперов мало было.

А>> А вот наоборот, отрубить его от OCaml уже нельзя.


DM>1. Зачем здравомыслящему человеку его вдруг отрубать?


Затем, что далеко не всегда и не везде нужна именно такая система типов. Затем, что для реализации DSLей нужно разнообразие возможностей, а не bondage and discipline.

DM> 2. Динамическая типизация делается на окамле элементарно, для работы с sexp'ами библиотек тоже предостаточно.


Я говорю про совсем отрубить, а не про частности.

A>> Из Лиспа можно сделать OCaml, или OCaml нельзя сделать эффективно Лисп. Следовательно, Лисп фундаментальнее.


DM>А Си еще фундаментальнее, не говоря о макроассемблере. Толку то.


Толку то, что Лисп — это метаязык, который тривиально превращается в любой другой язык. Чего не скажешь ни о Си, ни об OCaml-е.
Re[12]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 12.08.09 11:06
Оценка: 6 (1)
Здравствуйте, D. Mon, Вы писали:

А>> Не гораздо. Два-три часа максимум. Конкретнее — чуть больше тысячи строк кода с комментариями выходит.


DM>Мне, как и многим присутствующим, было бы очень интересно об этом почитать поподробнее. Можно ссылку или описание какое-нибудь?


Ну вот, например — аляповатый но примитивный компилятор ML на Лиспе:

http://www.meta-alternative.net/MBaseML.zip

Были где-то и ещё короче варианты.
Re[9]: Как написать виртуальную машину на LISP
От: Mr.Cat  
Дата: 12.08.09 11:35
Оценка:
Здравствуйте, Аноним, Вы писали:
А>Ну так вывод типов в Лиспе делается тривиально. А вот наоборот, отрубить его от OCaml уже нельзя. Из Лиспа можно сделать OCaml, или OCaml нельзя сделать эффективно Лисп. Следовательно, Лисп фундаментальнее.

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

И в ту, и в другую сторону получается хороший объем работы.
Так что я не разделяю твоих взглядов на то, что из чего делается и кто фундаментальнее.
Это как если мы начнем выяснять, что фундаментальнее: типизированное лямбда-исчисление или нетипизированное.
Re[11]: Как написать виртуальную машину на LISP
От: Mr.Cat  
Дата: 12.08.09 11:46
Оценка:
Здравствуйте, Аноним, Вы писали:
А> Толку то, что Лисп — это метаязык, который тривиально превращается в любой другой язык. Чего не скажешь ни о Си, ни об OCaml-е.
Не соглашусь. Что есть у макров лиспа:
1. Движок и язык преобразований дерева
2. Целевой язык с несложным форматом ast
Итого — просто набор уже готовых инструментов.
Если исходный язык прост или недалек от целевого — да, этот начальный набор инструментов сильно помогает.

В противном случае на любом другом языке можно реализовать пп. 1-2 и точно так же компилировать в лисп или другой подобный язык.
Или воспользоваться другим подобным набором инструментов. Вон, в antlr тоже вроде есть что-то готовое по работе с деревьями, в т.ч. язык для написания обходчиков/преобразователей дерева (могу ошибаться — давно я antlr-ом интересовался).
Будут те же яйца, вид в профиль.
Re[10]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 12.08.09 11:49
Оценка:
Здравствуйте, Mr.Cat, Вы писали:

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


Причём, компилятор из OCaml в Lisp. Остальное уже имеющийся в наличии компилятор Лиспа сам доделает.

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


А вот в этом случае придётся писать компилятор целиком. Работы больше на порядок.

MC>И в ту, и в другую сторону получается хороший объем работы.


Ты не видишь разницу между метаязыком и обычным, однопроходным языком?

MC>Так что я не разделяю твоих взглядов на то, что из чего делается и кто фундаментальнее.


Да не взгляды это. Всё тупо — то, что проще, из чего легче минимальный базис составить, то и фундаментальнее. Тут субъективным оценкам не место.

MC>Это как если мы начнем выяснять, что фундаментальнее: типизированное лямбда-исчисление или нетипизированное.


Term rewriting фундаментальнее. Любое лямбда-исчисление, алгоритмы Маркова, машины Тьюринга, и тому подобное — это всего лишь частные случаи.
Re[10]: Как написать виртуальную машину на LISP
От: Mr.Cat  
Дата: 12.08.09 11:54
Оценка:
Здравствуйте, thesz, Вы писали:
T>Давайте сравним современный Хаскель.
T>Вот и реализация Схемы есть: http://halogen.note.amherst.edu/~jdtang/scheme_in_48/tutorial/overview.html
Ну прям уж совсем порно. Хоть бы call/cc сделали. И макросы какие-нибудь простенькие:

On a more serious note, I do want to hold this up as an example
of how extremely simple and natural it is to implement
syntactic-closures compared to alternatives such as syntax-case.
The whole macro implementation is about 25 lines of low-level C
code
(modulo the extra lines I'll have to add later for bug
fixes), as opposed to say the 4000 or so lines of Scheme for
psyntax.

На хаскеле вообще тогда должно в одну строку писаться.
Re[12]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 12.08.09 11:57
Оценка:
Здравствуйте, Mr.Cat, Вы писали:

MC>Не соглашусь. Что есть у макров лиспа:

MC>1. Движок и язык преобразований дерева
MC>2. Целевой язык с несложным форматом ast

Самое важное:
3. Инкрементальный компилятор целевого языка.

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

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


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

MC>В противном случае на любом другом языке можно реализовать пп. 1-2 и точно так же компилировать в лисп или другой подобный язык.


И тогда у нас будет два разных языка. Никак не взаимодействующих.

MC>Или воспользоваться другим подобным набором инструментов. Вон, в antlr тоже вроде есть что-то готовое по работе с деревьями, в т.ч. язык для написания обходчиков/преобразователей дерева (могу ошибаться — давно я antlr-ом интересовался).


Ну и как, можно сам Antlr расширить средствами Antlr? Нельзя.

MC>Будут те же яйца, вид в профиль.


Совсем не те же. Любой метаязык заведомо превосходит любой не-метаязык. Даже если первый — это Форт, а второй — Haskell (без TH).
Re[13]: Как написать виртуальную машину на LISP
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 12.08.09 12:03
Оценка:
Здравствуйте, Аноним, Вы писали:

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

DM>Чтобы пример из первого поста (уже доступен, кстати) работал не 30 секунд, а 3, и при этом не надо было раздувать код аннотациями типов. Вот зачем.


Потом уважаемый Аноним стал говорить:

A>Ну так вывод типов в Лиспе делается тривиально. Из Лиспа можно сделать OCaml, или OCaml нельзя сделать эффективно Лисп. Следовательно, Лисп фундаментальнее.

A> Толку то, что Лисп — это метаязык, который тривиально превращается в любой другой язык. Чего не скажешь ни о Си, ни об OCaml-е.
А> Ну вот, например — аляповатый но примитивный компилятор ML на Лиспе:
А> http://www.meta-alternative.net/MBaseML.zip

Чем меня запутал. В архиве некий компилятор, который, используя готовый фреймворк, обычным образом парсит программу на МЛ и переводит ее в некое промежуточное представление, которое потом большая готовая библиотека вероятно компилит в MSIL. Т.е. сам лисп ни во что не превращается, то же самое так же делается и на любом другом языке. Вопросы:

1. Как из того, что на Лиспе можно воспользоваться генератором парсеров (входит в MBase), получается, что из Лиспа можно сделать Окамл? На нем можно сделать, но это совсем другое. Лисп в этом примере не превращается в другой язык, а просто парсит и компилирует, что можно и на Си делать. Где фундаментальность? Этим способом на окамле можно сделать какой угодно лисп.

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

PS. Похожие компиляторы мини-МЛ на окамле (см. Programming Language Zoo и MinCaml) выглядят лаконичнее и читабельнее, причем не используют больших фреймворков, скрывающих еще бабиллионы строк кода.

В общем, пока мне свет истины про лисп не открылся.
Re[14]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 12.08.09 12:15
Оценка: 6 (1)
Здравствуйте, D. Mon, Вы писали:

DM>Сначала ТС поделился своей реализацией ВМ из ICFPC на Лиспе. Я посетовал на ее медлительность и заметил, что причина может быть в том, что Лисп там не вывел типы, поэтому использовалась динамическая типизация, поэтому получилось медленно.


В том конкретном случае их и выводить не надо, кстати.

DM>Чем меня запутал. В архиве некий компилятор, который, используя готовый фреймворк,


ровно тот же самый Лисп. Любой Лисп таким фреймворком работать может.

DM> обычным образом парсит программу на МЛ и переводит ее в некое промежуточное представление,


В Лисп же и переводит.

DM> которое потом большая готовая библиотека вероятно компилит в MSIL.


В MSIL компилируется уже сам Лисп. Точно так же, если бы это было на SBCL, то "большой готовой библиотекой", которая компилирует это промежуточное представление, был бы сам SBCL. Потому как весь "компилятор" завёрнут в макру, которая разворачивает ML в Лисп и подставляет в месте вызова макры.

DM> Т.е. сам лисп ни во что не превращается, то же самое так же делается и на любом другом языке.


Как то же самое сделать на любом другом языке?

DM>1. Как из того, что на Лиспе можно воспользоваться генератором парсеров (входит в MBase), получается, что из Лиспа можно сделать Окамл?


А можно не пользоваться генератором парсеров. Можно использовать тот же самый алгоритм вывода типов для подмножества Лиспа. А это подмножество Лиспа генерить уже из макры (например, той, которая компилирует код VM).

DM> На нем можно сделать, но это совсем другое. Лисп в этом примере не превращается в другой язык, а просто парсит и компилирует, что можно и на Си делать.


Как это Лисп не превращается в другой язык? Можно написать так:

(lisp lisp lisp
(ml "let mlfunction args = something-mlish")
(lisp lisp call-ml-function lisp lisp ...))

DM> Где фундаментальность? Этим способом на окамле можно сделать какой угодно лисп.


Ну и как же? Где в OCaml есть macro, как я могу воспользоваться самим готовым компилятором OCaml? Да ещё и так, чтобы в том же модуле потом сослаться на результат компиляции?

DM>2. Как то, что на Лиспе можно сделать вывод типов для некоего внешнего языка, поможет в ускорении ВМ, написанной на самом Лиспе, если тормозит именно он?


Лисп позволяет вводить аннотации типов. А макронадстройка над Лиспом, выводящая типы автоматически, позволяет эти аннотации опускать.

DM>PS. Похожие компиляторы мини-МЛ на окамле (см. Programming Language Zoo и MinCaml) выглядят лаконичнее и читабельнее, причем не используют больших фреймворков, скрывающих еще бабиллионы строк кода.


Каких таких фреймворков? Там только лисповские макры. И я бы посмотрел на более лаконичную реализацию Хиндли-Милнера, чем компиляция в Пролог.

DM>В общем, пока мне свет истины про лисп не открылся.


Это нормально. Понять, что такое macro, многим удаётся далеко не сразу.
Re[14]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 12.08.09 12:27
Оценка:
Здравствуйте, D. Mon, Вы писали:

DM>2. Как то, что на Лиспе можно сделать вывод типов для некоего внешнего языка, поможет в ускорении ВМ, написанной на самом Лиспе, если тормозит именно он?



Уф, нашел таки наконец тот пример, который искал:

http://www.cliki.net/TypeL
Re[15]: Как написать виртуальную машину на LISP
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 12.08.09 13:01
Оценка:
Здравствуйте, Аноним, Вы писали:

А> Лисп позволяет вводить аннотации типов. А макронадстройка над Лиспом, выводящая типы автоматически, позволяет эти аннотации опускать.


Ок, я услышал, что Лисп — такой чудесный мега- т.е. мета-язык с чудо-компиляторами, на котором можно делать суперумные метапрограммы (наверняка именно на нем была написана программа, вычислившая ответ на жизнь, вселенную и вообще всего за 7,5 миллионов лет). И этот язык должен позволить решить исходную задачу (ВМ из ICFPC) очень легко и быстро, причем должно получиться лаконично и эффективно. И я даже понимаю умствования т.е. теорию, почему это так. Но без практики это лишь слова. Я готов уверовать в его силу, если увижу на нем реализацию вышеупомянутой ВМ, работающую не более чем в 2 раза медленнее варианта на Си и ее исходник будет не сильно длиннее окамловского. Спецификация ВМ очень проста, см. первый пост. Ссылка на вариант на Си тут была в теме про Окамл вс. С++.
Re: Как написать виртуальную машину на LISP
От: Turtle.BAZON.Group  
Дата: 12.08.09 13:03
Оценка:
Здравствуйте, Turtle.BAZON.Group, Вы писали:

TBG>HOWTO по написанию виртуальной машины на Common Lisp по спецификации из ICFPC-2009


Теперь и на lisper.ru. С расцветкой кода и ссылками на гиперспеку.
Re[11]: Как написать виртуальную машину на LISP
От: VoidEx  
Дата: 12.08.09 13:05
Оценка: +1 :))
Здравствуйте, Аноним, Вы писали:

А> Term rewriting фундаментальнее. Любое лямбда-исчисление, алгоритмы Маркова, машины Тьюринга, и тому подобное — это всего лишь частные случаи.


Я вот чо тока не понял, "фундаментальнее" — это ругательство или это круто типа? А то читаю и так и не пойму, у кого ж длиннее.
Re[11]: Как написать виртуальную машину на LISP
От: thesz Россия http://thesz.livejournal.com
Дата: 12.08.09 13:24
Оценка:
Здравствуйте, Аноним, Вы писали:

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


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

А> Не надо "примитивный". Надо "эффективный". Интерпретатор то минимального Лиспа любой дурак за час напишет.

Ну уж анализ-то кода на камле со сравнениями с образцом писать проще, чем на лиспе с CARами да CDRами.

А если подтянуть GADT из Хаскеля...

T>>Тогда как примитивный ОКамл на Лиспе потребует гораздо больше работы.

А> Не гораздо. Два-три часа максимум. Конкретнее — чуть больше тысячи строк кода с комментариями выходит.

А это будет "примитивный" или "эффективный" вариант?

Где бы на это посмотреть?

T>>К тому же зачем сравнивать уже устаревший ОКамл с мощным Лиспом.

А> Лисп как бы малость куда более "устаревший" и древний.
T>>Давайте сравним современный Хаскель.
А> Он слишком жирным стал в последнее время.

Потому, что в нём много удобных вещей.

T>>Вот и реализация Схемы есть: http://halogen.note.amherst.edu/~jdtang/scheme_in_48/tutorial/overview.html

А> Интерпретатор. Не интересно. Хотя, на Template Haskell теоретически и компилятор можно было бы сделать.

А нельзя ли показать, как это можно сделать с помощью TH? У меня это в голове не укладывается.

Вот пакеты кодогенерации:
http://hackage.haskell.org/packages/archive/pkg-list.html#cat:code%20generation

С их помощью я понимаю, как сделать. Как сделать с помощью TH, мне непонятно.

T>>Надо упомянуть, что ML был написан на Лиспе (и это на нём сказалось, см. The Zinc experiment) и на Лиспе же был написан один из первых компиляторов Хаскеля: Yake.

А> Да и YHC на Схеме написан. И что?

Так отошли от него.

Мой любимый аргумент: как много новых языков пишут на каком-либо ФЯ в последнее время?

На Хаскеле всё больше, на Лиспе с окамлом всё меньше.

А>>> Следовательно, Лисп фундаментальнее.

T>>По-моему, это поспешный вывод.
А> Ну почему же? Фундаментальность — понятие строгое.

А нельзя ли его привести?

T>>И ещё. "Фундаментальней" не значит "удобней".

А> Поскольку Лисп легко включает в себя весь ML, плюс много чего ещё, а в ML есть только ML — то да, удобнее. Но я не говорю "безопаснее", кстати.

Вот-вот.

Техника безопасности при работе с компьютером отличается по объёму от техники безопасности ведения боевых действий.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[16]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 12.08.09 13:29
Оценка:
Здравствуйте, D. Mon, Вы писали:

DM> Но без практики это лишь слова.


Ок, давай практику. Сделай на OCaml аналог макры ast:visit из MBase. То есть, рекурсивный обход ADT без явной рекурсии. Средствами OCaml. И чтоб работало так же эффективно, как вручную написанный код.

DM> Я готов уверовать в его силу, если увижу на нем реализацию вышеупомянутой ВМ,


Вышеупомянутая VM не имеет практической ценности.

DM> работающую не более чем в 2 раза медленнее варианта на Си и ее исходник будет не сильно длиннее окамловского. Спецификация ВМ очень проста, см. первый пост. Ссылка на вариант на Си тут была в теме про Окамл вс. С++.


Разве что если будет свободное время.

Интереснее было бы на более практичном примере сравнить. Только всё равно не спортивно — компилятор с интерпретатором пытаться сравнивать.
Re[12]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 12.08.09 13:38
Оценка:
Здравствуй

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

А>> Не надо "примитивный". Надо "эффективный". Интерпретатор то минимального Лиспа любой дурак за час напишет.

T>Ну уж анализ-то кода на камле со сравнениями с образцом писать проще, чем на лиспе с CARами да CDRами.


Как будто в Лиспах нет pattern matching-а. Есть, и погибче даже, чем в OCaml.

T>А если подтянуть GADT из Хаскеля...


Посмотри на эту реализацию ML на Лиспе — там более эффективное решение, чем GADT применяется.

T>>>Тогда как примитивный ОКамл на Лиспе потребует гораздо больше работы.

А>> Не гораздо. Два-три часа максимум. Конкретнее — чуть больше тысячи строк кода с комментариями выходит.

T>А это будет "примитивный" или "эффективный" вариант?


Примитивный, но эффективный (потому что всё же компилятор).

T>Где бы на это посмотреть?


Была уже ссылка на одну такую реализацию.

А>> Он слишком жирным стал в последнее время.


T>Потому, что в нём много удобных вещей.


Меня смущает необходимость пихать "удобные вещи" в минимальное ядро языка. Мне более интересен подход, когда "удобные вещи" легко и непринуждённо добавляются к языку средствами самого языка, но без ущерба эффективности. А то, что минимальный Хаскелль стал таким жирным, несколько отпугивает желающих его реализовать.

T>А нельзя ли показать, как это можно сделать с помощью TH? У меня это в голове не укладывается.


T>Вот пакеты кодогенерации:

T>http://hackage.haskell.org/packages/archive/pkg-list.html#cat:code%20generation

T>С их помощью я понимаю, как сделать. Как сделать с помощью TH, мне непонятно.


Кодогенерация + макра TH для подстановки этого самого сгенерённого кода во время компиляции.

T>Так отошли от него.


С YHC до сих пор носятся.

T>Мой любимый аргумент: как много новых языков пишут на каком-либо ФЯ в последнее время?


T>На Хаскеле всё больше, на Лиспе с окамлом всё меньше.


А на Java ещё больше, чем на всём остальном, вместе взятом. Это не показатель.

А>> Ну почему же? Фундаментальность — понятие строгое.


T>А нельзя ли его привести?


Несколько позже — сейчас с гарантией облажаюсь.

T>Техника безопасности при работе с компьютером отличается по объёму от техники безопасности ведения боевых действий.


Потому для меня идеалом является с одной стороны сколь угодно гибкая система, позволяющая делать сколь угодно опасные расширения, а с другой стороны, вся эта гибкость должна быть доступна только тем, кому она реально нужна. А остальным они должны предоставлять типобезопасный, верифицируемый, bondage'n'discipline интерфейс к своим сложным фичам.
Re[12]: Как написать виртуальную машину на LISP
От: Turtle.BAZON.Group  
Дата: 12.08.09 13:47
Оценка:
Здравствуйте, thesz, Вы писали:


T>Ну уж анализ-то кода на камле со сравнениями с образцом писать проще, чем на лиспе с CARами да CDRами.


Пример паттерн-матчинга в статье, кстати, есть.
Re[16]: Как написать виртуальную машину на LISP
От: Turtle.BAZON.Group  
Дата: 12.08.09 13:52
Оценка:
Здравствуйте, D. Mon, Вы писали:

А>> Ссылка на вариант на Си тут была в теме про Окамл вс. С++.


А можно более человеческий вариант получить? В том смысле, чтобы не дописывать, а сразу скомпилировать и запустить?
Re[17]: Как написать виртуальную машину на LISP
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 12.08.09 14:09
Оценка:
Здравствуйте, Turtle.BAZON.Group, Вы писали:

TBG>А можно более человеческий вариант получить? В том смысле, чтобы не дописывать, а сразу скомпилировать и запустить?


Использованные мной варианты:
http://stuff.thedeemon.com/orbitvm.cpp
http://stuff.thedeemon.com/orbitvm.ml

Дописать/раскомментировать нужно лишь что запускать — просто интерпретатор или с оптимизацией.
Re[18]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 12.08.09 14:10
Оценка:
Здравствуйте, D. Mon, Вы писали:

DM>Дописать/раскомментировать нужно лишь что запускать — просто интерпретатор или с оптимизацией.


А где взять тестовые данные от ICFPC?
Re[17]: Как написать виртуальную машину на LISP
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 12.08.09 14:17
Оценка:
Здравствуйте, Аноним, Вы писали:

DM>> Но без практики это лишь слова.

А> Ок, давай практику. Сделай на OCaml..

Кто кому что продает? Если я сделаю что-то на окамле, это про лисп ничего не докажет, кроме, может быть, его бесполезности.

A> аналог макры ast:visit из MBase. То есть, рекурсивный обход ADT без явной рекурсии.


А можно пример?

DM>> Я готов уверовать в его силу, если увижу на нем реализацию вышеупомянутой ВМ,


А> Вышеупомянутая VM не имеет практической ценности.


Ценность в практичном подтверждении слов. Отсутствие решения уж точно не имеет ценности.

А> Интереснее было бы на более практичном примере сравнить. Только всё равно не спортивно — компилятор с интерпретатором пытаться сравнивать.


А в каком месте интерпретатор? Вроде всю дорогу про компиляторы лиспа речь шла, про эффективность получаемых решений..
Re[15]: Как написать виртуальную машину на LISP
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 12.08.09 14:19
Оценка:
Здравствуйте, Аноним, Вы писали:

DM>>2. Как то, что на Лиспе можно сделать вывод типов для некоего внешнего языка, поможет в ускорении ВМ, написанной на самом Лиспе, если тормозит именно он?


А> Уф, нашел таки наконец тот пример, который искал:

А> http://www.cliki.net/TypeL

Features that will be implemented in feature releases:

1. Algebraic types and pattern matching.
2. Detailed error reporting.
3. Code optimization based on type information and static analysis.


Кажется, это контрпример. В нем нифига не реализовано.
Re[18]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 12.08.09 14:21
Оценка:
Здравствуйте, D. Mon, Вы писали:

DM>Кто кому что продает? Если я сделаю что-то на окамле, это про лисп ничего не докажет, кроме, может быть, его бесполезности.


Всё дело в том, что ты этого на OCaml не сделаешь. Не получится. Вообще. Не пустит он к себе в потроха, даже если CamlP4 использовать, до определения ADT добраться не дадут, чтоб макру правильно развернуть.

A>> аналог макры ast:visit из MBase. То есть, рекурсивный обход ADT без явной рекурсии.


DM>А можно пример?


http://www.meta-alternative.net/calc.pdf

Там простые примеры использования есть.

А>> Вышеупомянутая VM не имеет практической ценности.


DM>Ценность в практичном подтверждении слов. Отсутствие решения уж точно не имеет ценности.


Мотивация не очень-то мотивирующая. Посмотрим, если найду время прочитать спек на VM, тогда и реализовать её особого труда не составит.

DM>А в каком месте интерпретатор? Вроде всю дорогу про компиляторы лиспа речь шла, про эффективность получаемых решений..


Я как раз про то, что реализация на Лиспе — компилятор, а на C++ и ML — интерпретаторы.
Re[13]: Как написать виртуальную машину на LISP
От: thesz Россия http://thesz.livejournal.com
Дата: 12.08.09 14:24
Оценка: +1 :)
Здравствуйте, Аноним, Вы писали:

А>Здравствуй


T>>Ну уж анализ-то кода на камле со сравнениями с образцом писать проще, чем на лиспе с CARами да CDRами.

А> Как будто в Лиспах нет pattern matching-а. Есть, и погибче даже, чем в OCaml.

"Погибче" не означает "поудобней". А также это не означает "побезопасней".

Здесь присутствуют два бывших Лисповика, vshabanov и lomeo, оба покинули его и из-за невозможности нормального сравнения с образцом в том числе.

T>>А если подтянуть GADT из Хаскеля...

А> Посмотри на эту реализацию ML на Лиспе — там более эффективное решение, чем GADT применяется.

Где эта реализация, на которую надо посмотреть?

T>>>>Тогда как примитивный ОКамл на Лиспе потребует гораздо больше работы.

А>>> Не гораздо. Два-три часа максимум. Конкретнее — чуть больше тысячи строк кода с комментариями выходит.
T>>А это будет "примитивный" или "эффективный" вариант?
А> Примитивный, но эффективный (потому что всё же компилятор).

Похоже, что Lisp используется, как RTL в gcc.

А если мы ML в gcc странслируем, получится эффективней, или примитивней?

T>>Где бы на это посмотреть?

А> Была уже ссылка на одну такую реализацию.

Здесь не было. Где было-то?

А>>> Он слишком жирным стал в последнее время.

T>>Потому, что в нём много удобных вещей.
А> Меня смущает необходимость пихать "удобные вещи" в минимальное ядро языка. Мне более интересен подход, когда "удобные вещи" легко и непринуждённо добавляются к языку средствами самого языка, но без ущерба эффективности. А то, что минимальный Хаскелль стал таким жирным, несколько отпугивает желающих его реализовать.

Перечисли, пожалуйста, "удобные вещи", которые можно быстро добавить в Лисп и тяжело добавить в программу на Хаскеле. Если не сложно, то укажите альтернативные варианты и оцените их трудоемкость по написанию и использованию.

T>>А нельзя ли показать, как это можно сделать с помощью TH? У меня это в голове не укладывается.

T>>Вот пакеты кодогенерации:
T>>http://hackage.haskell.org/packages/archive/pkg-list.html#cat:code%20generation
T>>С их помощью я понимаю, как сделать. Как сделать с помощью TH, мне непонятно.
А> Кодогенерация + макра TH для подстановки этого самого сгенерённого кода во время компиляции.

Я не очень понимаю на словах.

Нельзя ли кода кусочек?

T>>Так отошли от него.

А> С YHC до сих пор носятся.

Как-то слабо.

T>>Мой любимый аргумент: как много новых языков пишут на каком-либо ФЯ в последнее время?

T>>На Хаскеле всё больше, на Лиспе с окамлом всё меньше.
А> А на Java ещё больше, чем на всём остальном, вместе взятом. Это не показатель.

Но не языков.

Поэтому и показатель, что языки сейчас делают на Хаскеле.

Видимо, это оптимум, sweet spot. И быстро, и безопасно.

T>>Техника безопасности при работе с компьютером отличается по объёму от техники безопасности ведения боевых действий.

А> Потому для меня идеалом является с одной стороны сколь угодно гибкая система, позволяющая делать сколь угодно опасные расширения, а с другой стороны, вся эта гибкость должна быть доступна только тем, кому она реально нужна. А остальным они должны предоставлять типобезопасный, верифицируемый, bondage'n'discipline интерфейс к своим сложным фичам.

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

Поэтому вопрос: software transactional memory для лиспа есть?
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[13]: Как написать виртуальную машину на LISP
От: thesz Россия http://thesz.livejournal.com
Дата: 12.08.09 14:26
Оценка:
Здравствуйте, Turtle.BAZON.Group, Вы писали:

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



T>>Ну уж анализ-то кода на камле со сравнениями с образцом писать проще, чем на лиспе с CARами да CDRами.


TBG>Пример паттерн-матчинга в статье, кстати, есть.


И им удобно пользоваться? Компилятор поможет, если структура сравниваемых значений изменилась?

Это очень важные вопросы.

Но я повторяюсь.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[16]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 12.08.09 14:27
Оценка:
Здравствуйте, D. Mon, Вы писали:

DM>Кажется, это контрпример. В нем нифига не реализовано.


А на фига для данной задачи всё остальное (ADT всякие, и т.д.)? Надо только малость похинтовать компилятор, чтоб с машинными целыми работал. А для этого и такой простой метод сгодится.
Re[14]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 12.08.09 14:36
Оценка:
Здравствуйте, thesz, Вы писали:

А>> Как будто в Лиспах нет pattern matching-а. Есть, и погибче даже, чем в OCaml.


T>"Погибче" не означает "поудобней". А также это не означает "побезопасней".


Про безопасность соглашусь. Но за безопасность приходится платить жестокостью системы типов. А удобство — это уже дело субъективное.

T>Здесь присутствуют два бывших Лисповика, vshabanov и lomeo, оба покинули его и из-за невозможности нормального сравнения с образцом в том числе.


Интересно было бы послушать, чего именно им не хватило.

T>Где эта реализация, на которую надо посмотреть?


Ранее в этой теме была ссылка.

А>> Примитивный, но эффективный (потому что всё же компилятор).


T>Похоже, что Lisp используется, как RTL в gcc.


Не совсем. RTL низкоуровневый и фиксированный. А Лисп можно специализировать под промежуточное представление для весьма сложных языков.

T>А если мы ML в gcc странслируем, получится эффективней, или примитивней?


Сложнее получится. И он не будет embedded.

T>Здесь не было. Где было-то?


Было-было.

T>Перечисли, пожалуйста, "удобные вещи", которые можно быстро добавить в Лисп и тяжело добавить в программу на Хаскеле.


Ну, например, систему типов. Как, например, в Qi II. Да, да, в Хаскелле уже есть одна, знаю. А я вот другую хочу. Как мне её поменять, не меняя языка?

Или, например, Пролог встроить хочу. Чтоб эффективно в WAM компилировался.

T> Если не сложно, то укажите альтернативные варианты и оцените их трудоемкость по написанию и использованию.


Альтернативный вариант — Template Haskell. Но у него свои сложности и ограничения есть. И я не уверен, что там всё в порядке с интроспекцией определений типов — давно в последний раз с ним играл.

T>Я не очень понимаю на словах.


T>Нельзя ли кода кусочек?


Ок, завтра пришлю простенький Лисп, сделанный на TH.

А>> А на Java ещё больше, чем на всём остальном, вместе взятом. Это не показатель.


T>Но не языков.


Именно языков. Из свежачка, например — Guru.

T>Видимо, это оптимум, sweet spot. И быстро, и безопасно.


Соглашусь, что это оптимум по скорости разработки и безопасности. Лисп — оптимум по скорости разработки и эффективности результата.

T>Вот именно. Здесь Хаскель рулит. Хочешь — добавляй свою фичу и поддерживай её.


А я не хочу. Меня не тянет копаться в разжиревших чрезмерно за последние годы потрохах GHC. И уж тем более поддерживать каждую нужную мне фичу вечно. Я хочу фичи добавлять точно так же, как пишутся библиотеки. И не трогать компилятор языка.

T>Поэтому вопрос: software transactional memory для лиспа есть?


CL-STM, например.
Re[14]: Как написать виртуальную машину на LISP
От: Turtle.BAZON.Group  
Дата: 12.08.09 14:40
Оценка:
Здравствуйте, thesz, Вы писали:

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


Вполне удобно. Если специфицирушь тип — поможет.
Re[18]: Как написать виртуальную машину на LISP
От: Turtle.BAZON.Group  
Дата: 12.08.09 14:47
Оценка:
Здравствуйте, D. Mon, Вы писали:

DM>Использованные мной варианты:

DM>http://stuff.thedeemon.com/orbitvm.cpp
DM>http://stuff.thedeemon.com/orbitvm.ml

DM>Дописать/раскомментировать нужно лишь что запускать — просто интерпретатор или с оптимизацией.


Что делать? В С++ не силён.

turtle@turtle:~/scm-controlled/turtle/icfpcontest/icfpcontest-2009/speedcon$ g++ orbitvm.cpp 
orbitvm.cpp:4:20: error: stdafx.h: No such file or directory                                 
orbitvm.cpp:6:21: error: windows.h: No such file or directory                                
orbitvm.cpp:24: ошибка: ‘DWORD’ не является именем типа
orbitvm.cpp: In constructor ‘VM::VM()’:
orbitvm.cpp:36: ошибка: нет декларации ‘prg’ в этой области видимости
orbitvm.cpp: In member function ‘bool VM::load_program(const char*)’:
orbitvm.cpp:42: ошибка: нет декларации ‘HANDLE’ в этой области видимости
orbitvm.cpp:42: ошибка: expected `;' before ‘h’
orbitvm.cpp:43: ошибка: нет декларации ‘h’ в этой области видимости
orbitvm.cpp:43: ошибка: нет декларации ‘INVALID_HANDLE_VALUE’ в этой области видимости
orbitvm.cpp:44: ошибка: нет декларации ‘DWORD’ в этой области видимости
orbitvm.cpp:44: ошибка: expected `;' before ‘sz’
orbitvm.cpp:45: ошибка: нет декларации ‘sz’ в этой области видимости
Re[19]: Как написать виртуальную машину на LISP
От: Turtle.BAZON.Group  
Дата: 12.08.09 14:49
Оценка:
Здравствуйте, Аноним, Вы писали:

А> А где взять тестовые данные от ICFPC?


В приложении к статье есть.
Re[18]: Как написать виртуальную машину на LISP
От: Turtle.BAZON.Group  
Дата: 12.08.09 15:02
Оценка:
Здравствуйте, D. Mon, Вы писали:

DM>http://stuff.thedeemon.com/orbitvm.cpp

DM>http://stuff.thedeemon.com/orbitvm.ml

Что-то пока не везёт с референсными имплементациями...

<code>
turtle@turtle:~/scm-controlled/turtle/icfpcontest/icfpcontest-2009/speedcon$ ocamlc orbitvm.ml
File "orbitvm.ml", line 4, characters 0-13:
Unbound module ExtArray
</code>
Re[19]: Как написать виртуальную машину на LISP
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 12.08.09 15:32
Оценка:
Здравствуйте, Аноним, Вы писали:

A> аналог макры ast:visit из MBase. То есть, рекурсивный обход ADT без явной рекурсии.

А> Всё дело в том, что ты этого на OCaml не сделаешь. Не получится. Вообще. Не пустит он к себе в потроха, даже если CamlP4 использовать, до определения ADT добраться не дадут, чтоб макру правильно развернуть.

Щито? Или я чего-то недопонял, или вот тут подобные вещи давно уже отличненько реализованы:
http://www.seedwiki.com/wiki/shifting_focus/tywith
http://code.google.com/p/deriving/wiki/Introduction

А> http://www.meta-alternative.net/calc.pdf


Из этого примера смысл ast:visit в МЛ ускользает — чем плох обычный рекурсивный обход дерева? В нем гораздо больше свободы действий плюс гарантия полноты матчинга и проверка корректности (проверяет ли ast:visit типы аргументов или хотя бы их число?), а текста немного, т.к. есть нормальный синтаксис.

DM>>А в каком месте интерпретатор? Вроде всю дорогу про компиляторы лиспа речь шла, про эффективность получаемых решений..


А> Я как раз про то, что реализация на Лиспе — компилятор, а на C++ и ML — интерпретаторы.


А, это да. Вот и интересно увидеть всю хваленую эффективность. А то пока что не видно.
Re[19]: Как написать виртуальную машину на LISP
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 12.08.09 15:35
Оценка:
Здравствуйте, Turtle.BAZON.Group, Вы писали:

TBG>Что-то пока не везёт с референсными имплементациями...


Вариант на С++, очевидно, виндовый (писал для себя, поэтому кроссплатформенность целью не была). А окамловый требует extLib, сорри.
Re[13]: Как написать виртуальную машину на LISP
От: Mr.Cat  
Дата: 12.08.09 15:38
Оценка:
Здравствуйте, Аноним, Вы писали:

A>Что позволяет любую сгенерённую во время компиляции конструкцию использовать тут же для определения следующих конструкций.

Это милая фича, не более того. Хитрые зависимости внутри одного модуля плодить совершенно не обязательно. В r6rs scheme, емнип, ввели стадии компиляции и эту фичу порезали — и ничего.

А> И тогда у нас будет два разных языка. Никак не взаимодействующих.

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

А> Совсем не те же. Любой метаязык заведомо превосходит любой не-метаязык. Даже если первый — это Форт, а второй — Haskell (без TH).

Никто не спорит, что метапрограммирование — это хорошая штука. В этой ветке мы сомневаемся в том, что метаязыки имеют какое-то волшебное преимущество при реализации компиляторов или интерпретаторов.
Re[15]: Как написать виртуальную машину на LISP
От: thesz Россия http://thesz.livejournal.com
Дата: 12.08.09 15:46
Оценка:
Здравствуйте, Turtle.BAZON.Group, Вы писали:

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


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


TBG>Вполне удобно. Если специфицирушь тип — поможет.


Связать полиморфные типы компилятор может?

А вот такое:
data Z
data S n
data Vec a len where
    Empty :: Vec Z
    Cons :: a -> Vec a n -> Vec a (S n)

safeHead :: Vec a (S n) -> a
safeHead (Cons a _) = a

-- ошибкой будет safeHead Empty.


Неужто тоже может?
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[15]: Как написать виртуальную машину на LISP
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 12.08.09 15:53
Оценка:
Здравствуйте, Аноним, Вы писали:

DM>> В архиве некий компилятор, который, используя готовый фреймворк,


А> ровно тот же самый Лисп. Любой Лисп таким фреймворком работать может.


Т.е. в любом Лиспе из коробки уже есть

# Natural abstract syntax trees support
# Efficient AST visitors' DSL
# Advanced pattern matching
# Embedded Prolog
# Various .NET type system oriented tools
# Easy to use lexing and parsing DSLs
# Trendy PEG/Packrat implementation
# Automatic generation of syntax highlighting and pretty-printing for every user-defined language

?

А> В MSIL компилируется уже сам Лисп. Точно так же, если бы это было на SBCL, то "большой готовой библиотекой", которая компилирует это промежуточное представление, был бы сам SBCL. Потому как весь "компилятор" завёрнут в макру, которая разворачивает ML в Лисп и подставляет в месте вызова макры.


А, так понятнее. А в решении из первого поста не так сделано, кстати?

DM>>PS. Похожие компиляторы мини-МЛ на окамле (см. Programming Language Zoo и MinCaml) выглядят лаконичнее и читабельнее, причем не используют больших фреймворков, скрывающих еще бабиллионы строк кода.


А> Каких таких фреймворков? Там только лисповские макры. И я бы посмотрел на более лаконичную реализацию Хиндли-Милнера, чем компиляция в Пролог.


Выше процитированы. И пролог тоже еще реализовать надо. Или он в любом лиспе есть встроенный?
Re[15]: Как написать виртуальную машину на LISP
От: thesz Россия http://thesz.livejournal.com
Дата: 12.08.09 16:00
Оценка:
Здравствуйте, Аноним, Вы писали:

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


А>>> Как будто в Лиспах нет pattern matching-а. Есть, и погибче даже, чем в OCaml.


T>>"Погибче" не означает "поудобней". А также это не означает "побезопасней".

А> Про безопасность соглашусь. Но за безопасность приходится платить жестокостью системы типов. А удобство — это уже дело субъективное.

Вполне объективное.

T>>Здесь присутствуют два бывших Лисповика, vshabanov и lomeo, оба покинули его и из-за невозможности нормального сравнения с образцом в том числе.

А> Интересно было бы послушать, чего именно им не хватило.

Ошибки вылезали. Система не отлавливала расхождений между создателем структур и их приёмником.

T>>Где эта реализация, на которую надо посмотреть?

А> Ранее в этой теме была ссылка.

Ранее в этой теме
Автор:
Дата: 12.08.09
не было ссылки.

А>>> Примитивный, но эффективный (потому что всё же компилятор).

T>>Похоже, что Lisp используется, как RTL в gcc.
А> Не совсем. RTL низкоуровневый и фиксированный. А Лисп можно специализировать под промежуточное представление для весьма сложных языков.

Это частности, если не вдаваться в подробности.

RTL тоже разные бывают.

T>>А если мы ML в gcc странслируем, получится эффективней, или примитивней?

А> Сложнее получится. И он не будет embedded.

Как часто нужен встроенный транслятор?

T>>Здесь не было. Где было-то?

А> Было-было.

Не было. Если было, то я хотел бы увидеть, где.

T>>Перечисли, пожалуйста, "удобные вещи", которые можно быстро добавить в Лисп и тяжело добавить в программу на Хаскеле.

А> Ну, например, систему типов. Как, например, в Qi II. Да, да, в Хаскелле уже есть одна, знаю. А я вот другую хочу. Как мне её поменять, не меняя языка?

Сменив язык?

Как в Лиспе решается вопрос с совмещение систем типов?

Как у фортеров с EXEC — "здесь типизируем, а вот здесь не типизируем", или, все же, по-другому?

А> Или, например, Пролог встроить хочу. Чтоб эффективно в WAM компилировался.


Monadic constraint programming?

T>> Если не сложно, то укажите альтернативные варианты и оцените их трудоемкость по написанию и использованию.

А> Альтернативный вариант — Template Haskell. Но у него свои сложности и ограничения есть. И я не уверен, что там всё в порядке с интроспекцией определений типов — давно в последний раз с ним играл.

Ценность метапрограммирования сильно преувеличена.

T>>Я не очень понимаю на словах.

T>>Нельзя ли кода кусочек?
А> Ок, завтра пришлю простенький Лисп, сделанный на TH.

Отлично.

А>>> А на Java ещё больше, чем на всём остальном, вместе взятом. Это не показатель.

T>>Но не языков.
А> Именно языков. Из свежачка, например — Guru.

Отлично. Idris/Ivor, Epigram, Agda2. Старенький Cayenne.

T>>Видимо, это оптимум, sweet spot. И быстро, и безопасно.

А> Соглашусь, что это оптимум по скорости разработки и безопасности. Лисп — оптимум по скорости разработки и эффективности результата.

Как определена "эффективность результата"?

T>>Вот именно. Здесь Хаскель рулит. Хочешь — добавляй свою фичу и поддерживай её.

А> А я не хочу. Меня не тянет копаться в разжиревших чрезмерно за последние годы потрохах GHC. И уж тем более поддерживать каждую нужную мне фичу вечно. Я хочу фичи добавлять точно так же, как пишутся библиотеки. И не трогать компилятор языка.

Большей частью они библиотеками и добавляются.

Почему я и сказал, что ценность метапрограммирования преувеличена.

T>>Поэтому вопрос: software transactional memory для лиспа есть?

А> CL-STM, например.

par/pseq?

Склейка вычислений (rewrite rules)?
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[20]: Как написать виртуальную машину на LISP
От: Turtle.BAZON.Group  
Дата: 12.08.09 16:50
Оценка:
Здравствуйте, D. Mon, Вы писали:

DM>Вариант на С++, очевидно, виндовый (писал для себя, поэтому кроссплатформенность целью не была). А окамловый требует extLib, сорри.


Ну вот... Так всегда. Хотя для окамла теперь, когда знаю как называется, нашёл либу, но ошибка та же.
Re[16]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 12.08.09 17:58
Оценка:
Здравствуйте, D. Mon, Вы писали:

DM>Т.е. в любом Лиспе из коробки уже есть


Зачем из коробки, когда есть http://www.cliki.net/
Re[20]: Как написать виртуальную машину на LISP
От: VoidEx  
Дата: 12.08.09 21:20
Оценка: :)
Здравствуйте, D. Mon, Вы писали:

DM>А, это да. Вот и интересно увидеть всю хваленую эффективность. А то пока что не видно.


Невольно вспоминается парадигма ленивого программирования. Программы на ЛИСПе пишутся только тогда, когда становится нужен их результат, а так как он никому не нужен, все программы на ЛИСПе можно считать написанными, причём работающими максимально быстро и не требующие памяти. Ну как-то так.
Re[21]: Как написать виртуальную машину на LISP
От: Mr.Cat  
Дата: 12.08.09 22:01
Оценка: 6 (1)
Оригинальная копипаста примерно такая:

LISPеры <...> пользуются технологией «ленивого программирования», аналогичной lazy evaluation.
При этом программа не пишется, а сразу объявляется написанной. Фактическое формирование кода программы должно происходить при первом непосредственном обращении к ней, но поскольку никто не обращается, код тоже не формируется.
Благодаря этому LISP разработчики экономят много времени, которое могут с пользой использоваться для эффективного троллинга.

Re[17]: Как написать виртуальную машину на LISP
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 13.08.09 02:36
Оценка:
Здравствуйте, Аноним, Вы писали:

DM>>Т.е. в любом Лиспе из коробки уже есть


А> Зачем из коробки, когда есть http://www.cliki.net/


Мне было сказано, что никакие дополнительные фреймворки/библиотеки не нужны, нужен только сам лисп:

DM> В архиве некий компилятор, который, используя готовый фреймворк,
A> ровно тот же самый Лисп. Любой Лисп таким фреймворком работать может.
A> Каких таких фреймворков? Там только лисповские макры. И я бы посмотрел на более лаконичную реализацию Хиндли-Милнера, чем компиляция в Пролог.

Re[12]: Как написать виртуальную машину на LISP
От: dmz Россия  
Дата: 13.08.09 04:40
Оценка: +2
T>>>Тогда как примитивный ОКамл на Лиспе потребует гораздо больше работы.
А>> Не гораздо. Два-три часа максимум. Конкретнее — чуть больше тысячи строк кода с комментариями выходит.

T>А это будет "примитивный" или "эффективный" вариант?


T>Где бы на это посмотреть?


Да что там смотреть? Mincaml — реализация подмножества окамла на окамле. С оптимизирующим компилятором для SPARC.
Около пятисот, что ли, строк. http://min-caml.sourceforge.net/index-e.html

Так что нашли чем похваляться. Около тысячи строк, блин. ML-и вообще очень простые для разбора языки.
Грамматика ml-подобных языков на Language Zoo занимает пару экранов максимум в ocamlyacc-файлах.

На camlp4 можно сделать компиляцию в AST окамла, поиметь семантические проверки нахаляву и сгенерить нативный код.
Или тоже самое, но при помощи биндингов к LLVM, примеры, кстати есть. Так что вообще непонятно, чем тут меряются.
Re[13]: Как написать виртуальную машину на LISP
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 13.08.09 04:43
Оценка:
Здравствуйте, Аноним, Вы писали:

А> Ну вот, например — аляповатый но примитивный компилятор ML на Лиспе:

А> http://www.meta-alternative.net/MBaseML.zip

Хм. Какой-то он неюзабельный: нет оптимизации хвостовой рекурсии и нет цикла for, т.е. поэтому цикл на 100000 итераций уже не получается сделать. А на таком коде просто умирает, разбрасывая кишки:
let repeat n f =
 let rec loop i =
   if (i `eq` n) then () else
     begin f (); loop (i+1) end in
 loop 0;;
 
repeat 10 (function ()-> () );;


repeat:: number -> ( unit -> 'alpha) -> unit
Exception (EMIT_ERR_P2 (class ("cZ152074_Z152098" NestedPublic) (extends
?:Meta.Scripting.AltClosure) (implements ?:Meta.Scripting.AltClosure1)
(field "f0" ?:System.Object (Public)) (constructor ("make" (Public HideBySig)
(Standard) (?:System.Object)) (Ldarg_0) (Call ?:Void .ctor()) (Ldarg_0)
(Ldarg_1) (Stfld (field f0)) (Ret)) (method ("run" (Public) (Standard)
?:System.Object (?:System.Object)) (local obj_1 ?:System.Object) (Ldnull)
(Ldarg_1) (Ldarg_0) (Ldfld (field f0)) (Newobj (method cZ152074_Z152090/make))
(Stloc (var obj_1)) (Ldloc (var obj_1)) (Castclass (class cZ152074_Z152090))
(Dup) (Ldloc (var obj_1)) (Stfld (field cZ152074_Z152090/f0)) (Pop) (Ldloc
(var obj_1)) (Ldc_I4 0) (Box ?:System.Int32) (Tailcall)
(Call ?:System.Object call_generic__1(System.Object, System.Object)) (Ret)))
"Выдано исключение типа \"Meta.Scripting.MBaseException\"." (INNER IN2
"cZ152074_Z152098" (EMIT_ERR_MTD_I "run" (EMIT:NOTFOUND cZ152074_Z152090
in clshash) ((local obj_1 ?:System.Object) (Ldnull) (Ldarg_1) (Ldarg_0)
(Ldfld (field f0)) (Newobj (method cZ152074_Z152090/make)) (Stloc (var obj_1))
(Ldloc (var obj_1)) (Castclass (class cZ152074_Z152090)) (Dup) (Ldloc (var
obj_1)) (Stfld (field cZ152074_Z152090/f0)) (Pop) (Ldloc (var obj_1))
(Ldc_I4 0) (Box ?:System.Int32) (Tailcall) (Call ?:System.Object
call_generic__1(System.Object, System.Object)) (Ret)))))
While expanding (ml-file "mltest2.ml")
SysException ?:System.NotSupportedException: Тип "mltest2.Z152117" не завершен.
в Meta.Scripting.SCWrapper.run(Object[] args)
в Meta.Scripting.MakeApp.run(Object[] frame)
в Meta.Scripting.MakeSequence.run(Object[] fr)
в Meta.Scripting.Runtime.eval(Object[] f)
в MBaseBin.Z768.mread_compile_eval0_Z677(Object )
в MBaseBin.Z768.mcore_read_int_eval_Z678(Object )
в MBaseBin.Z46321.mnew_read_int_eval_Z46318(Object )
в MBaseBin.Z46803.mcc_toplevel_expand_Z46635(Object , Object , Object , Object )
в MBaseBin.Z46803.mcc_toplevel_expand_Z46635(Object , Object , Object , Object )
в MBaseBin.Z46803.mcc_toplevel_devour_Z46636(Object , Object )
While expanding (n.save)


Хотел на скорость полюбоваться, не получилось.
Re[18]: Как написать виртуальную машину на LISP
От: Turtle.BAZON.Group  
Дата: 13.08.09 05:09
Оценка:
Здравствуйте, D. Mon, Вы писали:

DM>Мне было сказано, что никакие дополнительные фреймворки/библиотеки не нужны, нужен только сам лисп:


Тебе шашечки? Или ехать?
Re[16]: Как написать виртуальную машину на LISP
От: Turtle.BAZON.Group  
Дата: 13.08.09 05:13
Оценка:
Здравствуйте, thesz, Вы писали:

T>Неужто тоже может?


А как сам где-то в этой теме говоришь: "Ценность этого действа сильно преувеличена".
Если честно, даже проверять не хочу, потому что ценности этот пример для меня не имеет.
Re[20]: Как написать виртуальную машину на LISP
От: Turtle.BAZON.Group  
Дата: 13.08.09 07:41
Оценка:
Здравствуйте, D. Mon, Вы писали:

DM>Вариант на С++, очевидно, виндовый (писал для себя, поэтому кроссплатформенность целью не была). А окамловый требует extLib, сорри.


Тогда оптимизируй вот этот вариант.
Re[21]: Как написать виртуальную машину на LISP
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 13.08.09 08:00
Оценка:
Здравствуйте, Turtle.BAZON.Group, Вы писали:

TBG>Тогда оптимизируй вот этот вариант.


Зачем? Можно так с ним сравнить. Насколько сейчас отличается скорость твоего решения от данного интерпретатора?
Re[17]: Как написать виртуальную машину на LISP
От: thesz Россия http://thesz.livejournal.com
Дата: 13.08.09 08:33
Оценка:
Здравствуйте, Turtle.BAZON.Group, Вы писали:

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


T>>Неужто тоже может?


TBG>А как сам где-то в этой теме говоришь: "Ценность этого действа сильно преувеличена".


Я говорю, что ценность метапрограммирования преувеличена.

Так что действо вполне определённо.

Не надо меня толковать расширительно.

TBG>Если честно, даже проверять не хочу, потому что ценности этот пример для меня не имеет.


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

У нас, например, кое-где статически проверяется соответствие длин операндов и результатов. В bitvec a[10] можно присвоить результат mul(bitvec [5],bitvec [5]) или bitconcat(bitvec [3], bitvec [7]). Техника посложней, но в основе ровно то же самое.

Это то, о чем говорил аноним, утверждавший, что пользователю нужны сильно ограниченные и ограничивающие возможности.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[13]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 13.08.09 08:39
Оценка:
Здравствуйте, dmz, Вы писали:

dmz>Да что там смотреть? Mincaml — реализация подмножества окамла на окамле. С оптимизирующим компилятором для SPARC.

dmz>Около пятисот, что ли, строк. http://min-caml.sourceforge.net/index-e.html

Никак не 500, а побольше. И там даже pattern matching нет, совсем уж игрушечный ML.

dmz>Так что нашли чем похваляться. Около тысячи строк, блин. ML-и вообще очень простые для разбора языки.


Именно. О том и речь, что ML-подобный вывод типов к Лиспу прикрутить можно элементарно, после чего проблем с "лишними" аннотациями уже не будет.

dmz>Грамматика ml-подобных языков на Language Zoo занимает пару экранов максимум в ocamlyacc-файлах.


Грамматика в обсуждаемой задаче вообще не нужна. Нужен вывод типов.

dmz>На camlp4 можно сделать компиляцию в AST окамла, поиметь семантические проверки нахаляву и сгенерить нативный код.


Можно, конечно же. И это будет lisp way. Метапрограммирование. Простенькое, правда, однопроходное — но для такой задачи и это сойдёт.

dmz>Или тоже самое, но при помощи биндингов к LLVM, примеры, кстати есть. Так что вообще непонятно, чем тут меряются.


Тут обсуждают, а нужно ли вообще метапрограммирование, или и без него жить можно.
Re[18]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 13.08.09 08:49
Оценка:
Здравствуйте, thesz, Вы писали:

TBG>>А как сам где-то в этой теме говоришь: "Ценность этого действа сильно преувеличена".


T>Я говорю, что ценность метапрограммирования преувеличена.


Qi — по сути, расширение Лиспа. Да и Axiom тоже. И в Qi, и в Qi II, и в Axiom зависимые типы присутствуют.
Re[14]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 13.08.09 08:56
Оценка:
Здравствуйте, D. Mon, Вы писали:

DM>Хм. Какой-то он неюзабельный: нет оптимизации хвостовой рекурсии и нет цикла for, т.е. поэтому цикл на 100000 итераций уже не получается сделать. А на таком коде просто умирает, разбрасывая кишки:


А, ясненько. Это очень древняя версия. В свежей версии компилятора давно уже исправлен pattern matching. Это глюка не ML, а Лиспа. Добавить for там, кстати, можно очень легко.
Re[20]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 13.08.09 09:20
Оценка:
Здравствуйте, D. Mon, Вы писали:

DM>Щито? Или я чего-то недопонял, или вот тут подобные вещи давно уже отличненько реализованы:

DM>http://www.seedwiki.com/wiki/shifting_focus/tywith
DM>http://code.google.com/p/deriving/wiki/Introduction

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

DM>Из этого примера смысл ast:visit в МЛ ускользает — чем плох обычный рекурсивный обход дерева?


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

DM> В нем гораздо больше свободы действий


Не больше. Явный обход дерева — это частный случай.

DM> плюс гарантия полноты матчинга и проверка корректности (проверяет ли ast:visit типы аргументов или хотя бы их число?),


Проверяет

DM> а текста немного, т.к. есть нормальный синтаксис.


Синтаксис и там есть (см. PFront: http://lambda-the-ultimate.org/node/3281). А текста — очень много получается обычно, каким бы синтаксис не был.

Допустим, такая задача — есть AST довольно сложного языка, в котором, кроме всего прочего, есть конструкции let id = expr in expr и function (args) = expr;

Надо написать преобразование этого AST, такое, что каждое локально введённое имя будет заменяться на сгенерённый уникальный идентификатор.

В варианте со всякими там ML придётся писать рекурсивный обход всего дерева, не забывая ни одного пути, на котором может втретиться значение типа expr. И в каждом рекурсивном вызове тащить за собой ещё и окружение (таблицу переменования переменных). Очень многословно выходит. В варианте с ast:visit это будет несколько строчек, где из всего AST будут упомянуты только изменяемые узлы. Всё остальное будет сгенерено автоматически.

И такого типа простые преобразования деревьев в компиляторах очень типичны. Редко когда надо обойти всё дерево, чаще за один проход выполняется какое-то одно простое преобразование.
Re: Как написать виртуальную машину на LISP
От: meowth  
Дата: 13.08.09 09:38
Оценка: 4 (1)
Здравствуйте, Turtle.BAZON.Group, Вы писали:

TBG>HOWTO по написанию виртуальной машины на Common Lisp по спецификации из ICFPC-2009


Оно же, но на Nemerle — тыц-клац.
Re[2]: Как написать виртуальную машину на LISP
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 13.08.09 10:36
Оценка:
Здравствуйте, meowth, Вы писали:

TBG>>HOWTO по написанию виртуальной машины на Common Lisp по спецификации из ICFPC-2009


M>Оно же, но на Nemerle — тыц-клац.


Все-таки на .NET функциональщина тормозная выходит. Жалко.
Re[21]: Как написать виртуальную машину на LISP
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 13.08.09 10:47
Оценка:
Здравствуйте, Аноним, Вы писали:

DM>>Из этого примера смысл ast:visit в МЛ ускользает — чем плох обычный рекурсивный обход дерева?


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


А часто ли тип результата трансформации дерева совпадает с исходным? В моей практике — нечасто. Поэтому проверка типов просто не даст забыть преобразовать какой-нибудь случай.

Причем во многих случаях вполне сгодятся map и fold из tywith:
The following type definition:

  type 'a tree =
    | Leaf of 'a
    | Node of 'a tree * 'a tree
    with map, fold

Will generate functions with the following signatures:

  val map_tree : ('a -> 'b) -> 'a tree -> 'b tree
  val fold_tree : ('a -> 'b) -> ('b -> 'b -> 'b) -> 'a tree -> 'b


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

DM>> В нем гораздо больше свободы действий


А> Не больше. Явный обход дерева — это частный случай.


Не очевидно. Но я просто не знаю всех возможностей ast:visit.
Re[19]: Как написать виртуальную машину на LISP
От: thesz Россия http://thesz.livejournal.com
Дата: 13.08.09 10:54
Оценка:
Здравствуйте, Аноним, Вы писали:

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


TBG>>>А как сам где-то в этой теме говоришь: "Ценность этого действа сильно преувеличена".


T>>Я говорю, что ценность метапрограммирования преувеличена.


А> Qi — по сути, расширение Лиспа. Да и Axiom тоже. И в Qi, и в Qi II, и в Axiom зависимые типы присутствуют.


Я, как-то, спровоцировал войну в ru_lisp в ЖЖ.

Узнал много нового, например, что пользователю Qi удалось доказать, что 42 имеет тип "строка". Плюс, как выяснилось, никто из пользователей Lisp, присутствующих в ru_lisp, не использует Qi в своей работе.

Если хочется опровергнуть, то я бы попросил написать аналог кода для safeHead
Автор: thesz
Дата: 12.08.09
.

Мой вывод из всего этого таков: лисп остановился в развитии вместе с его пользователями. Вместо поиска путей конструктивных ограничений (Haskell, Agda2), его пользователи продолжают использовать его гибкость. Любые попытки внести такие ограничения в Лисп даже в виде расширений не используются в реальной работе, они используются только в рекламных целях и в целях поддержания огня священных войн.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[22]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 13.08.09 10:58
Оценка:
Здравствуйте, D. Mon, Вы писали:

DM>А часто ли тип результата трансформации дерева совпадает с исходным?


Очень часто. Большая часть преобразований именно такие.

DM> В моей практике — нечасто.


Часто компиляторы пишешь?

DM> Поэтому проверка типов просто не даст забыть преобразовать какой-нибудь случай.


Даже если и так — разве не напрягает все эти случаи расписывать, да ещё и везде менять код при изменении определения типа?

DM>В них уже можно подставлять конкретные функции преобразования частей.


И получается тормозятина. ast:visit не будет вообще переписывать те части дерева, которые не могут заведомо содержать изменяемые узлы. fold пройдётся по всему дереву целиком.

И для описанного случая (переименование переменных с lexical scoping) никакой fold не годится, поскольку тут нужно тащить контекст.

DM> Не очевидно. Но я просто не знаю всех возможностей ast:visit.


Посмотри на примеры, там всё довольно таки прозрачно. Наиболее полезная хитрая фича — else-deep. А при отключении стратегии DEEP это будет ровно то же самое, что просто рекурсивный обход дерева. Да, ещё конструкторы там есть удобные, в ML так сделать нельзя — см. макру ast:mknode.
Re[22]: Как написать виртуальную машину на LISP
От: Turtle.BAZON.Group  
Дата: 13.08.09 11:22
Оценка:
Здравствуйте, D. Mon, Вы писали:

DM> Зачем? Можно так с ним сравнить. Насколько сейчас отличается скорость твоего решения от данного интерпретатора?


Потому что сейчас вариант на С тормознее компилируемого варианта Lisp.
Re[20]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 13.08.09 11:22
Оценка:
Здравствуйте, thesz, Вы писали:

А>> Qi — по сути, расширение Лиспа. Да и Axiom тоже. И в Qi, и в Qi II, и в Axiom зависимые типы присутствуют.


T>Я, как-то, спровоцировал войну в ru_lisp в ЖЖ.


Ну в войнах то тролли участвуют. Всем остальным до них дела нет.

T>Узнал много нового, например, что пользователю Qi удалось доказать, что 42 имеет тип "строка". Плюс, как выяснилось, никто из пользователей Lisp, присутствующих в ru_lisp, не использует Qi в своей работе.


Я Axiom использую.

T>Мой вывод из всего этого таков: лисп остановился в развитии вместе с его пользователями.


Пользователи Лиспа не считают это направление "развитием". Есть более полезные для практики направления, куда стоит развиваться.

T> Вместо поиска путей конструктивных ограничений (Haskell, Agda2), его пользователи продолжают использовать его гибкость.


Ну не любят лисперы bondage&discipline. Не для всех это извращение, только немногие получают от этого удовольствие, большинству же и смотреть то противно, не то что участвовать.

T> Любые попытки внести такие ограничения в Лисп даже в виде расширений не используются в реальной работе,


Конечно, зачем лисперам то эти ограничения? Они используются в реальной работе тех самых DSLей, которые лисперы пользователям дают. И не по той причине, что пользователи любят садомазо, а чтоб им, пользователям, по ручкам шаловливым вовремя настучать, даже если им это и не понравится.
Re[23]: Как написать виртуальную машину на LISP
От: Turtle.BAZON.Group  
Дата: 13.08.09 12:16
Оценка:
Здравствуйте, Turtle.BAZON.Group, Вы писали:

TBG>Потому что сейчас вариант на С тормознее компилируемого варианта Lisp.


Немножко ошибся. Забыл, что на другом компьютере считал. Итак:

C++ 26 сек
Lisp (compiled) 37 сек
Lisp (interpreted) 64 сек

Но это ещё без оптимизаций — без деклараций типов и тому подобного.

turtle@turtle:~/scm-controlled/turtle/icfpcontest/icfpcontest-2009/speedcon$ time ./a.out ../task/bin1.obf 1001
267 frames loaded

real    0m25.736s
user    0m24.454s
sys     0m0.044s

* (time (bazon-icfpc-2009:start-vmc "../task/bin1.obf" 1001 :max-steps 1000000))

Evaluation took:
  37.156 seconds of real time
  36.886305 seconds of total run time (36.782299 user, 0.104006 system)
  [ Run times consist of 1.332 seconds GC time, and 35.555 seconds non-GC time. ]
  99.27% CPU
  924 lambdas converted
  66,877,744,221 processor cycles
  2,678,521,056 bytes consed

* (time (bazon-icfpc-2009:start-vmi "../task/bin1.obf" 1001 :max-steps 1000000))

Evaluation took:
  63.763 seconds of real time
  55.631477 seconds of total run time (55.543471 user, 0.088006 system)
  [ Run times consist of 1.048 seconds GC time, and 54.584 seconds non-GC time. ]
  87.25% CPU
  114,767,574,723 processor cycles
  2,656,352,744 bytes consed
Re[21]: Как написать виртуальную машину на LISP
От: thesz Россия http://thesz.livejournal.com
Дата: 13.08.09 12:22
Оценка:
Здравствуйте, Аноним, Вы писали:

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


А>>> Qi — по сути, расширение Лиспа. Да и Axiom тоже. И в Qi, и в Qi II, и в Axiom зависимые типы присутствуют.

T>>Я, как-то, спровоцировал войну в ru_lisp в ЖЖ.
А> Ну в войнах то тролли участвуют. Всем остальным до них дела нет.

Вот ты себя к кому относишь, к троллям, или ко всем остальным?

T>>Узнал много нового, например, что пользователю Qi удалось доказать, что 42 имеет тип "строка". Плюс, как выяснилось, никто из пользователей Lisp, присутствующих в ru_lisp, не использует Qi в своей работе.

А> Я Axiom использую.

Ура!

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

T>>Мой вывод из всего этого таков: лисп остановился в развитии вместе с его пользователями.

А> Пользователи Лиспа не считают это направление "развитием". Есть более полезные для практики направления, куда стоит развиваться.

Например?

T>> Любые попытки внести такие ограничения в Лисп даже в виде расширений не используются в реальной работе,

А> Конечно, зачем лисперам то эти ограничения? Они используются в реальной работе тех самых DSLей, которые лисперы пользователям дают. И не по той причине, что пользователи любят садомазо, а чтоб им, пользователям, по ручкам шаловливым вовремя настучать, даже если им это и не понравится.

Я не понимаю, зачем скатываться в "любят садомазо" на третьем или даже втором ответе.

Тем не менее, я продолжу.

Я считаю себя пользователем своих же творений.

Как только я написал функцию, я намерен её использовать.

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

Почему лисперы не считают себя пользователями своих же функций? Или считают? Если считают, то почему они не ограничивают себя, как других пользователей?
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[22]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 13.08.09 12:32
Оценка:
Здравствуйте, thesz, Вы писали:

T>Первый лиспер из множества участвовавших в обсуждениях с моим участием, что использует в своей работе систему типов.


Ну так я и Haskell использую, где-то треть кода пишется на нём.

T>>>Мой вывод из всего этого таков: лисп остановился в развитии вместе с его пользователями.

А>> Пользователи Лиспа не считают это направление "развитием". Есть более полезные для практики направления, куда стоит развиваться.

T>Например?


Техники реализации DSLей с хитрой семантикой. В которую может входить и сложная система типов. А может и не входить.

T>Я не понимаю, зачем скатываться в "любят садомазо" на третьем или даже втором ответе.


Сравнение типизации с bondage&discipline — давнее и устоявшееся. Лично я ничего в этом обидного не вижу. Лупть по рукам надо всех, в том числе и меня самого. При определённых обстоятельствах, конечно же.

T>Поскольку я признаю за собой право на ошибку и признаю за собой ответственность за ошибки в программе в целом, мне удобно, когда я сразу получаю по рукам. Даже если мне это и не нравится (вот сейчас с типами воюю).


Это всё прекрасно. Но, к сожалению, весьма плохо влияет на производительность труда.

T>Почему лисперы не считают себя пользователями своих же функций? Или считают? Если считают, то почему они не ограничивают себя, как других пользователей?


Ограничивают себя там, где вероятность ошибки велика, и оставляют себе свободу действий (и возможность быстрой разработки) там, где ошибка не страшна. А пользователя, который не знает хорошо всех внутренностей системы, ограничивают везде, где только можно.
Re[21]: Как написать виртуальную машину на LISP
От: thesz Россия http://thesz.livejournal.com
Дата: 13.08.09 12:52
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, D. Mon, Вы писали:


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


А вот при преобразовании AST (Where ::: Let ::: a) -> AST a (лямбда-лифтинг, убирающий where и let) типизация очень помогает.

Чьё отсутствие меня и бесило, когда я занимался компиляторами на "профессиональной" основе и пользовался библиотекой на C++.

А> Допустим, такая задача — есть AST довольно сложного языка, в котором, кроме всего прочего, есть конструкции let id = expr in expr и function (args) = expr;

А> Надо написать преобразование этого AST, такое, что каждое локально введённое имя будет заменяться на сгенерённый уникальный идентификатор.
А> В варианте со всякими там ML придётся писать рекурсивный обход всего дерева, не забывая ни одного пути, на котором может втретиться значение типа expr.

http://www.cs.vu.nl/boilerplate/

A>И в каждом рекурсивном вызове тащить за собой ещё и окружение (таблицу переменования переменных).


Для чего есть SYB поверх монад.

A>Очень многословно выходит.


Не так уж и многословно.

A>В варианте с ast:visit это будет несколько строчек, где из всего AST будут упомянуты только изменяемые узлы. Всё остальное будет сгенерено автоматически.


Как и в варианте с SYB.

А> И такого типа простые преобразования деревьев в компиляторах очень типичны. Редко когда надо обойти всё дерево, чаще за один проход выполняется какое-то одно простое преобразование.


Преобразующее одну из сторон AST. Какую именно, хорошо бы отмечать типом.

Кстати, не рекомендую сравнивать с ML. Сравнивать с Хаскелем куда круче.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[23]: Как написать виртуальную машину на LISP
От: thesz Россия http://thesz.livejournal.com
Дата: 13.08.09 12:59
Оценка:
Здравствуйте, Аноним, Вы писали:

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


T>>Первый лиспер из множества участвовавших в обсуждениях с моим участием, что использует в своей работе систему типов.

А> Ну так я и Haskell использую, где-то треть кода пишется на нём.

Это же кардинально меняет дело!

T>>>>Мой вывод из всего этого таков: лисп остановился в развитии вместе с его пользователями.

А>>> Пользователи Лиспа не считают это направление "развитием". Есть более полезные для практики направления, куда стоит развиваться.
T>>Например?
А> Техники реализации DSLей с хитрой семантикой. В которую может входить и сложная система типов. А может и не входить.

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

Может ли в реализацию DSL с хитрой семантикой входить простая система типов?

T>>Я не понимаю, зачем скатываться в "любят садомазо" на третьем или даже втором ответе.

А> Сравнение типизации с bondage&discipline — давнее и устоявшееся. Лично я ничего в этом обидного не вижу. Лупть по рукам надо всех, в том числе и меня самого. При определённых обстоятельствах, конечно же.

T>>Поскольку я признаю за собой право на ошибку и признаю за собой ответственность за ошибки в программе в целом, мне удобно, когда я сразу получаю по рукам. Даже если мне это и не нравится (вот сейчас с типами воюю).

А> Это всё прекрасно. Но, к сожалению, весьма плохо влияет на производительность труда.

Можно пример?

T>>Почему лисперы не считают себя пользователями своих же функций? Или считают? Если считают, то почему они не ограничивают себя, как других пользователей?

А> Ограничивают себя там, где вероятность ошибки велика, и оставляют себе свободу действий (и возможность быстрой разработки) там, где ошибка не страшна.

Вот "возможность быстрой разработки" меня смущает.

Поэтому я снова попрошу пример.

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


Если честно, то лично я не знаю особенностей работы системы практически никогда. Только моего узкого кусочка, что сейчас находится в разработке.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[24]: Как написать виртуальную машину на LISP
От: Andrei N.Sobchuck Украина www.smalltalk.ru
Дата: 13.08.09 15:01
Оценка:
Здравствуйте, Turtle.BAZON.Group, Вы писали:

TBG>C++ 26 сек

TBG>Lisp (compiled) 37 сек
TBG>Lisp (interpreted) 64 сек

2 замечания: ты измеряешь полное время компиляции + время выполнения. И всё это в цикле. Гораздо интереснее один раз откомпилировать (и померять время), а потом выполнить (и измерить отдельно).

И второе: в компиляционном варианте метод `vmc-arith-op` выглядит так:
(defun vmc-arith-op (ip data-memory arith-f r1 r2)
  `(setf (aref ,data-memory ,ip)
         (funcall ,arith-f
                  (aref ,data-memory ,r1)
                  (aref ,data-memory ,r2))))


Имхо, лучше вместо непрямого вызова через "funcall" сразу "инлайнить" вызов нужной арифметической операции.
Что-то навроде:
(defun vmc-arith-op (ip data-memory arith-f r1 r2)
  `(setf (aref ,data-memory ,ip)
         (,arith-f
                  (aref ,data-memory ,r1)
                  (aref ,data-memory ,r2))))

Нормальный компилятор для известной заранее арифметической операции может сразу генерировать более оптимальный код.
Я ненавижу Hibernate
Автор: Andrei N.Sobchuck
Дата: 08.01.08
!
Re[24]: Как написать виртуальную машину на LISP
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 13.08.09 15:54
Оценка:
Здравствуйте, Turtle.BAZON.Group, Вы писали:

TBG>Немножко ошибся. Забыл, что на другом компьютере считал. Итак:


TBG>C++ 26 сек

TBG>Lisp (compiled) 37 сек
TBG>Lisp (interpreted) 64 сек

На какой машине это запускалось и чем и как компилялся С++ вариант?
У меня он отрабатывает за 4,6 секунды. Ноутбук с Core 2 Duo 2.0 GHz, Windows Vista, Intel Compiler 7.1.

Неужто твоя машина в 5 раз медленнее?
Re[25]: Как написать виртуальную машину на LISP
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 13.08.09 15:57
Оценка:
DM>На какой машине это запускалось и чем и как компилялся С++ вариант?
DM>У меня он отрабатывает за 4,6 секунды.

Поправка: если тот же исходник компилю MSVC 6, то 3,75 секунды.
Re[25]: Как написать виртуальную машину на LISP
От: Turtle.BAZON.Group  
Дата: 13.08.09 19:03
Оценка:
Здравствуйте, D. Mon, Вы писали:

TBG>>C++ 26 сек

TBG>>Lisp (compiled) 37 сек
TBG>>Lisp (interpreted) 64 сек

DM>На какой машине это запускалось и чем и как компилялся С++ вариант?

DM>У меня он отрабатывает за 4,6 секунды. Ноутбук с Core 2 Duo 2.0 GHz, Windows Vista, Intel Compiler 7.1.

DM>Неужто твоя машина в 5 раз медленнее?


Вот таким образом:

g++ -std=c++0x vm.cpp


Машина 1.2 ГГц где-то два ядра. 32-битных. Ну знатоки, подскажите ключи компиляции для оптимизации.
Re[26]: Как написать виртуальную машину на LISP
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 14.08.09 02:33
Оценка: +1
Здравствуйте, Turtle.BAZON.Group, Вы писали:

TBG>Машина 1.2 ГГц где-то два ядра. 32-битных. Ну знатоки, подскажите ключи компиляции для оптимизации.


По gcc не знаток, но как минимум ключик -O2 стоит написать. Или можно попробовать -O3, вроде активный инлайнинг именно там включается.
Re[27]: Как написать виртуальную машину на LISP
От: Turtle.BAZON.Group  
Дата: 14.08.09 05:05
Оценка:
Здравствуйте, D. Mon, Вы писали:

DM>По gcc не знаток, но как минимум ключик -O2 стоит написать. Или можно попробовать -O3, вроде активный инлайнинг именно там включается.


В корку падает.
Re[28]: Как написать виртуальную машину на LISP
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 14.08.09 06:22
Оценка:
Здравствуйте, Turtle.BAZON.Group, Вы писали:

TBG>В корку падает.


Кто и когда?
Re[15]: Как написать виртуальную машину на LISP
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 14.08.09 07:44
Оценка:
Здравствуйте, Аноним, Вы писали:

T>>Здесь присутствуют два бывших Лисповика, vshabanov и lomeo, оба покинули его и из-за невозможности нормального сравнения с образцом в том числе.

А> Интересно было бы послушать, чего именно им не хватило.

Ну, я не "лисповик", а schemer, CL баловался постольку-поскольку.

Если кратко — не хватало статической типизации. Субъективно — на Haskell, с которым я тогда был знаком меньше, разработка была быстрее.

Большинство из того, что мне нравилось в scheme, есть или не нужно (решаются схожие задачи по другому) в Haskell. В том числе и макросы. Это не к вопросу о Тьюринг-полноте, разумеется, а к вопросу об удобстве.

О Qi знаю. Не понимаю зачем он. По моему, сила лиспа в динамике в том числе.

P.S. Scheme мне очень нравится и я до сих пор иногда (правда, всё реже) её использую.
Re[22]: Как написать виртуальную машину на LISP
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 14.08.09 07:46
Оценка:
Здравствуйте, thesz, Вы писали:

A>>В варианте с ast:visit это будет несколько строчек, где из всего AST будут упомянуты только изменяемые узлы. Всё остальное будет сгенерено автоматически.


T>Как и в варианте с SYB.


Тут такой прикол — в ast:visit, насколько я понял, будет сгенерен эффективный код доступа к полю структуры, а в SYB — нет (cast-ы будут), разве что на TH его переписать.
Re[23]: Как написать виртуальную машину на LISP
От: thesz Россия http://thesz.livejournal.com
Дата: 14.08.09 08:33
Оценка:
Здравствуйте, lomeo, Вы писали:

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


A>>>В варианте с ast:visit это будет несколько строчек, где из всего AST будут упомянуты только изменяемые узлы. Всё остальное будет сгенерено автоматически.

T>>Как и в варианте с SYB.
L>Тут такой прикол — в ast:visit, насколько я понял, будет сгенерен эффективный код доступа к полю структуры, а в SYB — нет (cast-ы будут), разве что на TH его переписать.

И это никак не лечится путём переписывания и оптимизаций?..

Можно, вообще, представить алгоритм, который оптимизирует SYB код до кода ast:visit? Разворачиванием словарей классов, например.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[24]: Как написать виртуальную машину на LISP
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 14.08.09 09:42
Оценка:
Здравствуйте, thesz, Вы писали:

T>И это никак не лечится путём переписывания и оптимизаций?..


А как переписывать, если структура нам заранее не известна? Насчёт оптимизаций — не могу такую придумать.

T>Можно, вообще, представить алгоритм, который оптимизирует SYB код до кода ast:visit? Разворачиванием словарей классов, например.


Не понял идею.

Смысл в том, что если есть структура, скажем

data Base = Base ... [Sub] ...

data Sub = Sub ... someField :: SubSub ...

data SubSub = SS Int


и мы хотим сделать например

gmap (\SubSub i -> SubSub (i + 1)) base


то это должно развернуться в

gmapBase (Base ... subs ...) = Base{subs = gmapList subs}
gmapList = map gmapSub -- лень писать
gmapSub Sub{someField} = Sub{someField = gmapSubSub someField}
gmapSubSub (SubSub i) = SubSub (i + 1)


Зная структуру заранее, т.е. во время компиляции, мы это можем сделать. gmap же (SYB) работает runtime.
Re[25]: Как написать виртуальную машину на LISP
От: thesz Россия http://thesz.livejournal.com
Дата: 14.08.09 12:37
Оценка:
Здравствуйте, lomeo, Вы писали:

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


T>>И это никак не лечится путём переписывания и оптимизаций?..


L>А как переписывать, если структура нам заранее не известна? Насчёт оптимизаций — не могу такую придумать.


T>>Можно, вообще, представить алгоритм, который оптимизирует SYB код до кода ast:visit? Разворачиванием словарей классов, например.


L>Не понял идею.


L>Смысл в том, что если есть структура, скажем


L>
L>data Base = Base ... [Sub] ...

L>data Sub = Sub ... someField :: SubSub ...

L>data SubSub = SS Int
L>


L>и мы хотим сделать например


L>
L>gmap (\SubSub i -> SubSub (i + 1)) base
L>


L>то это должно развернуться в


L>
L>gmapBase (Base ... subs ...) = Base{subs = gmapList subs}
L>gmapList = map gmapSub -- лень писать
L>gmapSub Sub{someField} = Sub{someField = gmapSubSub someField}
L>gmapSubSub (SubSub i) = SubSub (i + 1)
L>


L>Зная структуру заранее, т.е. во время компиляции, мы это можем сделать. gmap же (SYB) работает runtime.


Как же лиспу удаётся знать структуру заранее? Знает ли компилятор Хаскеля ту же структуру заранее?

Я думаю, что компилятор Хаскеля всё это знает. Единственное, что остаётся, это реализовать это знание.

Это возможно сделать вот, как: зная тип, к которому мы собираемся применить gmap (\SubSub i -> SubSub (i + 1)) base, мы можем вычислить, какие поля каких вариантов этого типа могут иметь не провальное применение gmap. Вроде, для не полиморфных типов это не очень сложно — если поле типа, содержащего SubSub, то успех, если поле примитивного типа, отличного от типа SubSub, то применение будет провальным всегда, если тип составной, то провальность применения определяется рекурсией, что мы только что описали.

Видимо, это никому особенно не нужно, проводить такие оптимизации. Вот их и нет.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[26]: Как написать виртуальную машину на LISP
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 14.08.09 13:46
Оценка:
Здравствуйте, thesz, Вы писали:

T>Это возможно сделать вот, как: зная тип, к которому мы собираемся применить gmap (\SubSub i -> SubSub (i + 1)) base, мы можем вычислить, какие поля каких вариантов этого типа могут иметь не провальное применение gmap. Вроде, для не полиморфных типов это не очень сложно — если поле типа, содержащего SubSub, то успех, если поле примитивного типа, отличного от типа SubSub, то применение будет провальным всегда, если тип составной, то провальность применения определяется рекурсией, что мы только что описали.


Только после следующей фразы понял, что ты говоришь про оптимизацию

T>Видимо, это никому особенно не нужно, проводить такие оптимизации. Вот их и нет.


Не аргумент. Во всяких Generic Haskell такую функцию написать можно. Оптимизации нет, потому что уж очень она специфичная — для конкретной функции, уж не проще ли функцию тогда реализовать на TH, или, возможно, на Generic Type Classes.
Re[27]: Как написать виртуальную машину на LISP
От: thesz Россия http://thesz.livejournal.com
Дата: 14.08.09 14:54
Оценка:
Здравствуйте, lomeo, Вы писали:

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


T>>Видимо, это никому особенно не нужно, проводить такие оптимизации. Вот их и нет.

L>Не аргумент. Во всяких Generic Haskell такую функцию написать можно.

А много ли народу пишет?

L>Оптимизации нет, потому что уж очень она специфичная — для конкретной функции, уж не проще ли функцию тогда реализовать на TH, или, возможно, на Generic Type Classes.


О!

Кстати.

Спасибо.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[29]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 16.08.09 07:58
Оценка:
Здравствуйте, D. Mon, Вы писали:

DM>Кто и когда?


Программа при запуске.
Re[15]: Как написать виртуальную машину на LISP
От: thesz Россия http://thesz.livejournal.com
Дата: 16.08.09 10:11
Оценка:
Здравствуйте, Аноним, Вы писали:

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


А> Альтернативный вариант — Template Haskell. Но у него свои сложности и ограничения есть. И я не уверен, что там всё в порядке с интроспекцией определений типов — давно в последний раз с ним играл.


T>>Я не очень понимаю на словах.

T>>Нельзя ли кода кусочек?
А> Ок, завтра пришлю простенький Лисп, сделанный на TH.

То "завтра" было позавчера или даже раньше, поэтому осторожно поинтересуюсь прогрессом.

Не готов ли простенький Лисп поверх TH?
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[20]: Как написать виртуальную машину на LISP
От: Курилка Россия http://kirya.narod.ru/
Дата: 16.08.09 20:07
Оценка:
Здравствуйте, thesz, Вы писали:

T>Здравствуйте, Аноним, Вы писали:


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


TBG>>>>А как сам где-то в этой теме говоришь: "Ценность этого действа сильно преувеличена".


T>>>Я говорю, что ценность метапрограммирования преувеличена.


А>> Qi — по сути, расширение Лиспа. Да и Axiom тоже. И в Qi, и в Qi II, и в Axiom зависимые типы присутствуют.


T>Я, как-то, спровоцировал войну в ru_lisp в ЖЖ.


T>Узнал много нового, например, что пользователю Qi удалось доказать, что 42 имеет тип "строка". Плюс, как выяснилось, никто из пользователей Lisp, присутствующих в ru_lisp, не использует Qi в своей работе.


Дак даж автор Qi уходит
Re[28]: Как написать виртуальную машину на LISP
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 17.08.09 07:11
Оценка:
Здравствуйте, thesz, Вы писали:

T>>>Видимо, это никому особенно не нужно, проводить такие оптимизации. Вот их и нет.

L>>Не аргумент. Во всяких Generic Haskell такую функцию написать можно.
T>А много ли народу пишет?

Не знаю. Но то, что в SYB неэффективное решение — я вижу.

Вот одно из решений — Alloy: Fast Generic Transformations for Haskell. Вместо использования дорогого на каждом шаге cast, там втупую генерятся экземпляры класса типов (аналогично строкам функции (по ПМ) в моём примере, по экземпляру на строку). Если поменять на генерацию строк, должно быть ещё быстрее.

Важно, что это возможно. А сколько народу пишет — неважно, да и не знаю я.

Ещё подумал — undecideable instances ведь тоже можно использовать в качестве generic programming. Ведь это тоже форма генерации экземпляров. Но это так — мысли в сторону.
Re[16]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 17.08.09 08:16
Оценка:
Здравствуйте, thesz, Вы писали:

А>> Ок, завтра пришлю простенький Лисп, сделанный на TH.


T>То "завтра" было позавчера или даже раньше, поэтому осторожно поинтересуюсь прогрессом.


Опачки, склероз!

T>Не готов ли простенький Лисп поверх TH?


http://pastebin.com/f4ee79fd7

Что-то там хреново работает раскраска синтаксиса. Ну да ладно, фигня.

В общем, я пока только одного придумать не могу — как defmacro реализовать (и связанная с этим задача — глобальные определения констант). Протащить контекст между top level expressions в TH нельзя, а уж тем более между модулями. Нужен какой-то грязный хак.
Re[26]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 17.08.09 08:21
Оценка:
Здравствуйте, thesz, Вы писали:

L>>Зная структуру заранее, т.е. во время компиляции, мы это можем сделать. gmap же (SYB) работает runtime.


T> Как же лиспу удаётся знать структуру заранее?


Определения типов есть, конкретный визитор есть — остальное выводится.

T> Знает ли компилятор Хаскеля ту же структуру заранее?


Знать то он знает, да только вклиниться из Template Haskell в compilation pipeline не дадут, информацию о типах не дадут, да даже определения посмотреть не позволят. Никакой рефлексии. А без reflection метапрограммирование убого и ограниченно.

T>Я думаю, что компилятор Хаскеля всё это знает. Единственное, что остаётся, это реализовать это знание.


Внутри компилятора — запросто. Сторонней библиотекой — фигушки.

T>Видимо, это никому особенно не нужно, проводить такие оптимизации. Вот их и нет.


Лисповодам вон нужно же. О скорости заботятся.
Re[21]: Как написать виртуальную машину на LISP
От: thesz Россия http://thesz.livejournal.com
Дата: 17.08.09 08:37
Оценка: :))
Здравствуйте, Курилка, Вы писали:

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


T>>Узнал много нового, например, что пользователю Qi удалось доказать, что 42 имеет тип "строка". Плюс, как выяснилось, никто из пользователей Lisp, присутствующих в ru_lisp, не использует Qi в своей работе.

К>Дак даж автор Qi уходит

Я старался не приводить этот аргумент. Я подумал, что это удар ниже пояса.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[27]: Как написать виртуальную машину на LISP
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 17.08.09 09:00
Оценка:
Здравствуйте, Аноним, Вы писали:

T>> Знает ли компилятор Хаскеля ту же структуру заранее?

А> Знать то он знает, да только вклиниться из Template Haskell в compilation pipeline не дадут, информацию о типах не дадут

И даже reify не поможет?
Re[27]: Как написать виртуальную машину на LISP
От: thesz Россия http://thesz.livejournal.com
Дата: 17.08.09 09:05
Оценка:
Здравствуйте, Аноним, Вы писали:

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


L>>>Зная структуру заранее, т.е. во время компиляции, мы это можем сделать. gmap же (SYB) работает runtime.

T>> Как же лиспу удаётся знать структуру заранее?
А> Определения типов есть, конкретный визитор есть — остальное выводится.

Наверное, то же самое можно сделать и в Хаскеле?

Или нет?

T>> Знает ли компилятор Хаскеля ту же структуру заранее?

А> Знать то он знает, да только вклиниться из Template Haskell в compilation pipeline не дадут,

rewrite rules

GHC plugins (будущее)

А>информацию о типах не дадут,


reify

A>да даже определения посмотреть не позволят.


(a,b) = something

Чему равен a?

Just a = anotherthing

Чему равен a?

А>Никакой рефлексии. А без reflection метапрограммирование убого и ограниченно.


Что Брукс писал про метапрограммирование?

T>>Я думаю, что компилятор Хаскеля всё это знает. Единственное, что остаётся, это реализовать это знание.

А> Внутри компилятора — запросто. Сторонней библиотекой — фигушки.

Плагины к GHC. Оформляются в виде сторонних библиотек.

T>>Видимо, это никому особенно не нужно, проводить такие оптимизации. Вот их и нет.

А> Лисповодам вон нужно же. О скорости заботятся.

Они простые задачи решают. Поэтому и стараются выиграть в скорости, просто для того, чтобы в хоть в чём-то выиграть.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[28]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 17.08.09 09:07
Оценка:
Здравствуйте, lomeo, Вы писали:

T>>> Знает ли компилятор Хаскеля ту же структуру заранее?

А>> Знать то он знает, да только вклиниться из Template Haskell в compilation pipeline не дадут, информацию о типах не дадут

L>И даже reify не поможет?


Только в некоторых ограниченных случаях, похоже.
Re[28]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 17.08.09 09:15
Оценка:
Здравствуйте, lomeo, Вы писали:

L>И даже reify не поможет?


А вообще я похоже зря гоню. Почему-то считал, что он хреново работает с определениями из других модулей. Проверил — таки нормально работает. Тогда, возможно, такое и на TH сделать получится.
Re[28]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 17.08.09 09:20
Оценка:
Здравствуйте, thesz, Вы писали:

T>Наверное, то же самое можно сделать и в Хаскеле?


Можно. Но сложно.

T>GHC plugins (будущее)


Отдалённое. А работать сейчас надо.

А>>информацию о типах не дадут,


T>reify


Уже понял, что зря на него гнал. С ним раньше проблемы были, но похоже уже всё исправили.

A>>да даже определения посмотреть не позволят.


T>(a,b) = something


T>Чему равен a?


T>Just a = anotherthing


T>Чему равен a?


Я про глобальные определения говорю.

А>>Никакой рефлексии. А без reflection метапрограммирование убого и ограниченно.


T>Что Брукс писал про метапрограммирование?


Мне наплевать на мнение Брукса по этому поводу.

T>>>Я думаю, что компилятор Хаскеля всё это знает. Единственное, что остаётся, это реализовать это знание.

А>> Внутри компилятора — запросто. Сторонней библиотекой — фигушки.

T>Плагины к GHC. Оформляются в виде сторонних библиотек.


Когда ещё я этим смогу на практике воспользоваться...

T>>>Видимо, это никому особенно не нужно, проводить такие оптимизации. Вот их и нет.

А>> Лисповодам вон нужно же. О скорости заботятся.

T>Они простые задачи решают.


Именно. Компиляторы — это очень, очень просто. Не надо усложнять то, что можно сделать легко и непринуждённо.

T> Поэтому и стараются выиграть в скорости, просто для того, чтобы в хоть в чём-то выиграть.


В скорости разработки и читабельности кода тоже одни только выигрыши в конкретно этой задаче (компиляторы).
Re[29]: Как написать виртуальную машину на LISP
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 17.08.09 09:25
Оценка:
Здравствуйте, Аноним, Вы писали:

L>>И даже reify не поможет?

А> А вообще я похоже зря гоню. Почему-то считал, что он хреново работает с определениями из других модулей. Проверил — таки нормально работает. Тогда, возможно, такое и на TH сделать получится.

Угу, получится. Внешний вид будет, конечно, не такой красивый, как при прямом вызове функции.
Re[29]: Как написать виртуальную машину на LISP
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 17.08.09 09:53
Оценка:
Здравствуйте, Аноним, Вы писали:

T>>(a,b) = something

T>>Чему равен a?
T>>Just a = anotherthing
T>>Чему равен a?
А> Я про глобальные определения говорю.

А это глобальные, так тоже можно

T>>Плагины к GHC. Оформляются в виде сторонних библиотек.

А> Когда ещё я этим смогу на практике воспользоваться...

К сожалению, документация по потрохам GHC для написания этих плагинов очень слабая.

T>>>>Видимо, это никому особенно не нужно, проводить такие оптимизации. Вот их и нет.

А>>> Лисповодам вон нужно же. О скорости заботятся.
T>>Они простые задачи решают.
А> Именно. Компиляторы — это очень, очень просто. Не надо усложнять то, что можно сделать легко и непринуждённо.

T>> Поэтому и стараются выиграть в скорости, просто для того, чтобы в хоть в чём-то выиграть.

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

(жую попкорн, вылупив зенки)...
Re[29]: Как написать виртуальную машину на LISP
От: thesz Россия http://thesz.livejournal.com
Дата: 17.08.09 11:17
Оценка:
Здравствуйте, Аноним, Вы писали:

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


T>>Наверное, то же самое можно сделать и в Хаскеле?


А> Можно. Но сложно.

T>>GHC plugins (будущее)
А> Отдалённое. А работать сейчас надо.

Сейчас можно и без метапрограммирования.

Типы (особенно, ассоциированные) рулят.

A>>>да даже определения посмотреть не позволят.

T>>(a,b) = something
T>>Чему равен a?
T>>Just a = anotherthing
T>>Чему равен a?
А> Я про глобальные определения говорю.

Это и есть "глобальные определения".

(a,b) = findGoodPair [пары]


А>>>Никакой рефлексии. А без reflection метапрограммирование убого и ограниченно.

T>>Что Брукс писал про метапрограммирование?
А> Мне наплевать на мнение Брукса по этому поводу.

О!

А что по этому поводу писал МакКарти?

T>>>>Я думаю, что компилятор Хаскеля всё это знает. Единственное, что остаётся, это реализовать это знание.

А>>> Внутри компилятора — запросто. Сторонней библиотекой — фигушки.
T>>Плагины к GHC. Оформляются в виде сторонних библиотек.
А> Когда ещё я этим смогу на практике воспользоваться...

Своевременно, или несколько позже.

T>>>>Видимо, это никому особенно не нужно, проводить такие оптимизации. Вот их и нет.

А>>> Лисповодам вон нужно же. О скорости заботятся.
T>>Они простые задачи решают.
А> Именно. Компиляторы — это очень, очень просто.

Да, если есть типы.

Я уже приводил пример с преобразованием (AST (WHERE ::: LET)).

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

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


Именно! Именно!

Поэтому не стоит приплетать оптимизацию по скорости там, где нужна точная логика.

T>> Поэтому и стараются выиграть в скорости, просто для того, чтобы в хоть в чём-то выиграть.

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

Это желательно бы подтвердить.

Компилятор чего ты разрабатывал последнее время?

Я — VHDL, например. Практически синтезатор большого его подмножества.

Два месяца работы вместе с рантаймом.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[30]: Как написать виртуальную машину на LISP
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 17.08.09 18:40
Оценка:
Здравствуйте, Аноним, Вы писали:

DM>>Кто и когда?


А>Программа при запуске.


Или не так запускаете (правильный способ выше приведен), или какой-то странный у вас компилятор С++ (это если без оптимизаций не падает, а с ними падает).
Re[17]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 18.08.09 08:33
Оценка:
Здравствуйте, Аноним, Вы писали:

А> В общем, я пока только одного придумать не могу — как defmacro реализовать (и связанная с этим задача — глобальные определения констант). Протащить контекст между top level expressions в TH нельзя, а уж тем более между модулями. Нужен какой-то грязный хак.


Ну так что, подскажет кто православный способ делиться контекстом между сплайсами и православный способ эмуляции рефлексии?
Re[18]: Как написать виртуальную машину на LISP
От: thesz Россия http://thesz.livejournal.com
Дата: 18.08.09 08:45
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, Аноним, Вы писали:


А>> В общем, я пока только одного придумать не могу — как defmacro реализовать (и связанная с этим задача — глобальные определения констант). Протащить контекст между top level expressions в TH нельзя, а уж тем более между модулями. Нужен какой-то грязный хак.


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


Типы классов с ассоциированными типами?

Ты лучше саму задачу опиши, может быть, поможем.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[19]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 18.08.09 08:51
Оценка:
Здравствуйте, thesz, Вы писали:

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


T>Типы классов с ассоциированными типами?


Не покатит.

T>Ты лучше саму задачу опиши, может быть, поможем.


Задача — добавить в этот игрушечный Лисп конструкцию defmacro, иначе это не Лисп, а отстой. Для этого нужно, всего-то — по имени функции с известным типом (да, ладно уж, смиримся с этим — пусть она определена в другом модуле) получить возможность её вызвать. Или узнать, что такой функции нет. Примерно то же самое, то есть, что делает сам template haskell, когда раскрывает сплайс (но он то как раз это делает не-православным способом, насколько я смог понять реализацию).
Re[20]: Как написать виртуальную машину на LISP
От: thesz Россия http://thesz.livejournal.com
Дата: 18.08.09 10:26
Оценка:
Здравствуйте, Аноним, Вы писали:

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


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

T>>Типы классов с ассоциированными типами?
А> Не покатит.

А ты пробовал?

T>>Ты лучше саму задачу опиши, может быть, поможем.

А> Задача — добавить в этот игрушечный Лисп конструкцию defmacro, иначе это не Лисп, а отстой. Для этого нужно, всего-то — по имени функции с известным типом (да, ладно уж, смиримся с этим — пусть она определена в другом модуле) получить возможность её вызвать. Или узнать, что такой функции нет. Примерно то же самое, то есть, что делает сам template haskell, когда раскрывает сплайс (но он то как раз это делает не-православным способом, насколько я смог понять реализацию).

Понятно.

Это не для работы, а для доказательства в споре.

Неинтересно.

В реальной жизни такие проблемы не встречаются.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[21]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 18.08.09 10:53
Оценка:
Здравствуйте, thesz, Вы писали:

А>> Не покатит.


T>А ты пробовал?


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

T>Понятно.


Сомневаюсь.

T>Это не для работы, а для доказательства в споре.


Я никому ничего доказать не пытаюсь, успокойся. Не можешь — так сразу и скажи. Это не страшно — мало ли кто чего не может.

T>В реальной жизни такие проблемы не встречаются.


Ещё как встречаются. Очень часто приходится разрабатывать [e]DSL-и, в которых нужна та или иная степень рефлексии и метапрограммирования. Да, это в принципе можно сделать в TH, но это невозможно сделать по-православному. Я уж не говорю о том, что любой грязный хак будет нестабилен — поменяют в очередной раз API в GHC, и опачки.

И, да, я не намерен спорить на тему компиляция vs. интерпретация. Для очень многих моих задач интерпретируемые решения не годятся принципиально. Среди причин — не только производительность, но ещё и защита от reverse engineering. Всякий бред про "метапрограммирование не нужно" мне выслушивать абсолютно не интересно — мне оно нужно, и я с ним делаю то, что другими способами сделать невозможно в принципе.

Самым православным решением для такого рода рефлексии в TH было бы расширить монаду Q, добавив туда, грубо говоря, возможность вызова runMeta из TcSplice.lhs; Это не противоречит никакой религии, и расширило бы гибкость метапрограммирования до уровня любого из современных Лиспов. Тогда бы у лисповодов и все претензии к Хаскеллю закончились разом, наступил бы всеобщий мир и процветание.
Re[21]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 18.08.09 11:27
Оценка:
Здравствуйте, thesz, Вы писали:


T>В реальной жизни такие проблемы не встречаются.


P.S. В реальной жизни JVM и .NET используются гораздо чаще, чем Haskell. И в них очень, очень часто используется reflection. Так что я бы поостерёгся сводить дискуссию к "реальной жизни" — уж больно там много примеров применения рефлексии.
Re[22]: Как написать виртуальную машину на LISP
От: thesz Россия http://thesz.livejournal.com
Дата: 18.08.09 13:55
Оценка:
Здравствуйте, Аноним, Вы писали:

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


А>>> Не покатит.

T>>А ты пробовал?
А> В этой конкретной задаче — нет смысла. API фиксированное, я ничего с ним сделать не могу.

Ну, кое-что мне подсказывает, что "нет смысла" в твоих устах не много значит.

Ты несколько раз ошибся насчёт Template Haskell. Вполне можешь ошибаться и насчёт ассоциированных типов.

T>>Понятно.

А> Сомневаюсь.

Я очень умный, не сомневайся.

T>>Это не для работы, а для доказательства в споре.

А> Я никому ничего доказать не пытаюсь, успокойся. Не можешь — так сразу и скажи. Это не страшно — мало ли кто чего не может.

Не было вопроса о том, что "я не могу". Поэтому не было и признаний в том, что я не могу.

А так — да, не могу.

Оно мне не надо.

T>>В реальной жизни такие проблемы не встречаются.

А> Ещё как встречаются. Очень часто приходится разрабатывать [e]DSL-и, в которых нужна та или иная степень рефлексии и метапрограммирования.

Приведи пример.

А> Да, это в принципе можно сделать в TH, но это невозможно сделать по-православному.


Иными словами, в стиле Лиспа.

А> И, да, я не намерен спорить на тему компиляция vs. интерпретация.

А> Для очень многих моих задач интерпретируемые решения не годятся принципиально. Среди причин — не только производительность, но ещё и защита от reverse engineering.

Так можно сделать кодогенерацию с компиляцией, зачем в toplevel-то встраивать.

А> Всякий бред про "метапрограммирование не нужно" мне выслушивать абсолютно не интересно — мне оно нужно, и я с ним делаю то, что другими способами сделать невозможно в принципе.


Я бы хотел увидеть пример.

А> Самым православным решением для такого рода рефлексии в TH было бы расширить монаду Q, добавив туда, грубо говоря, возможность вызова runMeta из TcSplice.lhs; Это не противоречит никакой религии, и расширило бы гибкость метапрограммирования до уровня любого из современных Лиспов. Тогда бы у лисповодов и все претензии к Хаскеллю закончились разом, наступил бы всеобщий мир и процветание.


По-моему, причина, по которой это трудно сделать, проста: проверка типов.

А вообще, я задал вопрос в Haskell cafe. Посмотрим.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[22]: Как написать виртуальную машину на LISP
От: thesz Россия http://thesz.livejournal.com
Дата: 18.08.09 13:57
Оценка:
Здравствуйте, Аноним, Вы писали:

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



T>>В реальной жизни такие проблемы не встречаются.


А>P.S. В реальной жизни JVM и .NET используются гораздо чаще, чем Haskell. И в них очень, очень часто используется reflection. Так что я бы поостерёгся сводить дискуссию к "реальной жизни" — уж больно там много примеров применения рефлексии.


Им по-другому нельзя.

Рефлексия необходима, когда нет механизма deriving и классов типов, посмотрите на типичные случаи применения.

Поэтому, в реальной жизни, рефлексия применяется в тех случаях, когда не хватает языковых средств.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[23]: Как написать виртуальную машину на LISP
От: Mamut Швеция http://dmitriid.com
Дата: 18.08.09 14:31
Оценка: :)
t> А> Сомневаюсь.

t> Я очень умный, не сомневайся.


И сильный. И вообще сильно умный, да.

avalon 1.0rc2 rev 295, zlib 1.2.3 (01.08.2009 02:47:12 EEST :z)(Qt 4.5.1)


dmitriid.comGitHubLinkedIn
Re[23]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 18.08.09 15:08
Оценка:
Здравствуйте, thesz, Вы писали:

А>> В этой конкретной задаче — нет смысла. API фиксированное, я ничего с ним сделать не могу.


T>Ну, кое-что мне подсказывает, что "нет смысла" в твоих устах не много значит.


Ну и как я могу изменить определение монады Quasi, не пересобирая ghc?

T> Ты несколько раз ошибся насчёт Template Haskell.


Да, ошибался — мои знания th устарели, раньше reify действительно глючил. Но сейчас я смотрю в свеженькие исходники из darcs и всё равно не вижу, как я могу вклиниться в поведение сплайсов не меняя самого ghc.

T> Вполне можешь ошибаться и насчёт ассоциированных типов.


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

T>>>Понятно.

А>> Сомневаюсь.

T>Я очень умный, не сомневайся.


Я сомневаюсь, что по одной этой частной и до предела упрощённой задаче можно понять область применимости рефлексии для метапрограммирования на TH. Никакой зашкаливающий IQ не поможет.

T>А так — да, не могу.


Об этом и речь. И я не могу. Но хочу.

T>Оно мне не надо.


А вот мне — надо. Судя по убожеству всех мною виденных примеров применения TH, другим не то что "не надо", а просто не задумывался никто о подобных вещах. Потому и пробелы в API.

T>>>В реальной жизни такие проблемы не встречаются.

А>> Ещё как встречаются. Очень часто приходится разрабатывать [e]DSL-и, в которых нужна та или иная степень рефлексии и метапрограммирования.

T>Приведи пример.


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

А>> Да, это в принципе можно сделать в TH, но это невозможно сделать по-православному.


T>Иными словами, в стиле Лиспа.


Нет, как раз в стиле Лиспа, с глобальным состоянием, сделать можно. А по-православному, чисто-функционально, чтоб это тянулось в монаде Quasi — нельзя.

А>> И, да, я не намерен спорить на тему компиляция vs. интерпретация.

А>> Для очень многих моих задач интерпретируемые решения не годятся принципиально. Среди причин — не только производительность, но ещё и защита от reverse engineering.

T>Так можно сделать кодогенерацию с компиляцией, зачем в toplevel-то встраивать.


Если это EDSL? Препроцессоры городить — это позорная сиплюсплюсщина. Метапрограммирование на то и нужно, чтоб без препроцессоров обходиться.

А>> Всякий бред про "метапрограммирование не нужно" мне выслушивать абсолютно не интересно — мне оно нужно, и я с ним делаю то, что другими способами сделать невозможно в принципе.


T>Я бы хотел увидеть пример.


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

T>По-моему, причина, по которой это трудно сделать, проста: проверка типов.


С чего бы это вдруг? Тип как раз известен заранее. Нужно найти в уже импортированных модулях определение с таким-то именем и этим известным типом. Всё абсолютно строго, никакого простора для грязных хаков не остаётся. Для ML я это делал. Да даже делегаты в .NET — тоже типобезопасны, насколько это возможно в рамках .NETовской системы типов. Тут проблем никаких нет, реализация самого runMeta вполне православная, без хаков. Просто банально об этом никто не подумал.

T>А вообще, я задал вопрос в Haskell cafe. Посмотрим.


Да, я не исключаю, что может найтись какое-то решение. Но вообще с продуманностью API у TH серьёзные проблемы.
Re[23]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 18.08.09 15:15
Оценка:
Здравствуйте, thesz, Вы писали:

T>Им по-другому нельзя.


Это так.

T>Рефлексия необходима, когда нет механизма deriving и классов типов, посмотрите на типичные случаи применения.


Тогда уж она необходима, когда нет метапрограммирования. А для метапрограммирования нужна как минимум рефлексия времени компиляции. Типичное применение — всякие там ORM-ы, сериализаторы, и т.п. Deriving слишком частный случай того самого метапрограммирования, не всё в этот частный случай вписывается.

T>Поэтому, в реальной жизни, рефлексия применяется в тех случаях, когда не хватает языковых средств.


В реальной жизни рефлексия как раз является способом реализации этих самых языковых средств.

Да, я не настаиваю на наличии метаданных во время выполнения, но при компиляции иметь доступ к метаданным — совершенно необходимо.
Re[24]: Как написать виртуальную машину на LISP
От: thesz Россия http://thesz.livejournal.com
Дата: 18.08.09 16:29
Оценка:
Здравствуйте, Аноним, Вы писали:

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


А>>> В этой конкретной задаче — нет смысла. API фиксированное, я ничего с ним сделать не могу.

T>>Ну, кое-что мне подсказывает, что "нет смысла" в твоих устах не много значит.
А> Ну и как я могу изменить определение монады Quasi, не пересобирая ghc?

А это-то здесь причём?

T>> Ты несколько раз ошибся насчёт Template Haskell.

А> Да, ошибался — мои знания th устарели, раньше reify действительно глючил. Но сейчас я смотрю в свеженькие исходники из darcs и всё равно не вижу, как я могу вклиниться в поведение сплайсов не меняя самого ghc.

И не надо.

Может, для решения хватит ассоциированных типов и типов классов?

T>> Вполне можешь ошибаться и насчёт ассоциированных типов.

А> Я прекрасно представляю, как семантику, аналогичную рефлексии, сделать на уровне системы типов Хаскелля. Проблема в том, что этого не сделано в его API-из-коробки, в том, которое я, как пользователь, менять не могу.

А ты здесь не ошибешься ли?

T>>>>Понятно.

А>>> Сомневаюсь.
T>>Я очень умный, не сомневайся.
А> Я сомневаюсь, что по одной этой частной и до предела упрощённой задаче можно понять область применимости рефлексии для метапрограммирования на TH. Никакой зашкаливающий IQ не поможет.

Мой IQ вполне способен.

T>>А так — да, не могу.

А> Об этом и речь. И я не могу. Но хочу.

Лично я, обычно, хочу решить задачу, а не решить задачу определённым образом.

Собственно, моё напоминание об отсутствии решения было как раз для напоминания о том, что идиоматическое решение на Хаскеле отлично от идиоматического решения в стиле Лиспа, с метапрограммированием и прочей рефлексией.

T>>Оно мне не надо.

А> А вот мне — надо. Судя по убожеству всех мною виденных примеров применения TH, другим не то что "не надо", а просто не задумывался никто о подобных вещах. Потому и пробелы в API.

А почему не задумывались, не задумывался?

Быть может, хватает обычного Хаскеля? Быть может, твоя формулировка решения ненадёжна или невыгодна?

T>>>>В реальной жизни такие проблемы не встречаются.

А>>> Ещё как встречаются. Очень часто приходится разрабатывать [e]DSL-и, в которых нужна та или иная степень рефлексии и метапрограммирования.
T>>Приведи пример.
А> Любой DSL, в котором компиляция может смешиваться с интерпретацией во время выполнения. То есть, часть кода на этом DSL компилируется в Haskell и пользователю не видна, но он может, например, в конфигурационном файле или в коммандной строке (когда компилятор уже не доступен и не должен быть доступен) вводить код на том же или производном DSL, и ссылаться при этом на компилированные определения.

Это слишком общий пример. Тем не менее.

А> Очень частая ситуация, в моей практике гораздо чаще смешанный режим исполнения встречается, чем чистая компиляция или чистая интерпретация.


А что за область деятельности?

А> Понятно, что для реализации такой интерпретации нужны некоторые метаданные во время исполнения. Сейчас приходится извращаться. Была бы полноценная рефлексия — жить было бы проще.


Этого можно достичь кодогенерацией.

А>>> Да, это в принципе можно сделать в TH, но это невозможно сделать по-православному.

T>>Иными словами, в стиле Лиспа.
А> Нет, как раз в стиле Лиспа, с глобальным состоянием, сделать можно. А по-православному, чисто-функционально, чтоб это тянулось в монаде Quasi — нельзя.

Ладно.

Чего нам там нужно было? Вызов функции с определёнными параметрами из определённого модуля, если таковой существует?

Можно ли добиться требуемого тебе результат, если подняться на ещё один уровень в вызовах Template Haskell?

Что-то типа:
$(processModuleDefs [d|
  ... moduledefs ...
  $(compileFunc [d| ... func |]
  ... moduledefs ...
  |])


Поможет ли такой вариант? Ведь в processModuleDefs мы можем собрать всю нужную нам информацию и добавить специальную функцию для обращения к ней.

А>>> И, да, я не намерен спорить на тему компиляция vs. интерпретация.

А>>> Для очень многих моих задач интерпретируемые решения не годятся принципиально. Среди причин — не только производительность, но ещё и защита от reverse engineering.
T>>Так можно сделать кодогенерацию с компиляцией, зачем в toplevel-то встраивать.
А> Если это EDSL? Препроцессоры городить — это позорная сиплюсплюсщина. Метапрограммирование на то и нужно, чтоб без препроцессоров обходиться.

Комбинаторы?

Как много комбинаторных библиотек ты написал?

А>>> Всякий бред про "метапрограммирование не нужно" мне выслушивать абсолютно не интересно — мне оно нужно, и я с ним делаю то, что другими способами сделать невозможно в принципе.

T>>Я бы хотел увидеть пример.
А> Не имею ни настроения, ни времени спорить. Надеялся, что моя конкретная практическая задача найдёт какое либо элегантное решение — не вышло. А доказывать преимущества метапрограммирования я не собираюсь. В конце концов, чем меньше людей понимает его потенциальные возможности, тем меньше конкуренция.

Тем меньше развитие.

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

К тому же метапрограммирование само по себе не имеет ценности. Оно имеет ценность в качестве одного из инструментов.

Если оно действительно настолько мощно и настолько применимо (и безопасно и просто в использовании, это важно), то предъявить пример не составило бы труда.

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

T>>По-моему, причина, по которой это трудно сделать, проста: проверка типов.

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

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

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

Наверное.

Вот, например:
{-# LANGUAGE ScopedTypeVariables #-}

module A where

import Data.Maybe
import Language.Haskell.TH
import Data.Generics

processModule decls = do
    decls <- decls
    runIO $ putStrLn $ pprint decls
    let modules = concatMap maybeToList $
        map nameModule $ listify (\(_::Name) -> True) decls
    runIO $ putStrLn $ show modules
    return decls


Вот его пользователь:
{-# LANGUAGE TemplateHaskell #-}

module B where

import A
import Language.Haskell.TH

$(processModule [d|
    main = do
        mapM test "Hello, world!"
    test c = putStrLn $ show c
  |])


Вывод ghci при загрузке B.hs:
[1 of 2] Compiling A                ( A.hs, interpreted )
[2 of 2] Compiling B                ( B.hs, interpreted )
main = do Control.Monad.mapM test "Hello, world!"
test c_0 = System.IO.putStrLn GHC.Base.$ GHC.Show.show c_0
["Control.Monad","System.IO","GHC.Base","GHC.Show"]
Ok, modules loaded: B, A.


(бляха муха, я даже чуток понял Data.Generics в процессе! вот она, польза приведения примеров

В общем и целом, я думаю, что Лисп-в-стиле-Лиспа на Хаскеле не получится.

Потому, что API TH под это не заточено. Оно заточено под другие дела.

Ну, так и нечего стараться.

Помниться, мне макросов хотелось недели две, пока до функций высшего порядка не дошёл.

А> Всё абсолютно строго, никакого простора для грязных хаков не остаётся. Для ML я это делал. Да даже делегаты в .NET — тоже типобезопасны, насколько это возможно в рамках .NETовской системы типов. Тут проблем никаких нет, реализация самого runMeta вполне православная, без хаков. Просто банально об этом никто не подумал.


T>>А вообще, я задал вопрос в Haskell cafe. Посмотрим.

А> Да, я не исключаю, что может найтись какое-то решение. Но вообще с продуманностью API у TH серьёзные проблемы.

Я так не думаю.

Над ним работали мощнейшие умы планеты Земля.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[24]: Как написать виртуальную машину на LISP
От: thesz Россия http://thesz.livejournal.com
Дата: 18.08.09 16:38
Оценка: +1 :)
Здравствуйте, Mamut, Вы писали:

t>> А> Сомневаюсь.


t>> Я очень умный, не сомневайся.


M>И сильный. И вообще сильно умный, да.


И скромный.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[25]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 18.08.09 17:18
Оценка:
Здравствуйте, thesz, Вы писали:

А>>>> В этой конкретной задаче — нет смысла. API фиксированное, я ничего с ним сделать не могу.

T>>>Ну, кое-что мне подсказывает, что "нет смысла" в твоих устах не много значит.
А>> Ну и как я могу изменить определение монады Quasi, не пересобирая ghc?

T>А это-то здесь причём?


При том, что мы говорим о вполне конкретном случае применения рефлексии — внутри сплайса, для приложения поименованной функции из другого модуля с известной сигнатурой типа. То есть, о работе с API собственно GHC.

T>Может, для решения хватит ассоциированных типов и типов классов?


Не вижу такого решения. Ещё раз повторю формулировку задачи — есть код, сгенерённый внутри сплайса в каком-то другом модуле — функция "macro_blahblahblah", в которую было откомпилированно определение defmacro. Есть распарсенный лисповский список, голова которого — символ "blahblahblah". Надо получить результат приложения функции macro_blahblahblah :: LispV -> LispV к остатку этого списка. Конечно кроме функции можно генерить и тип, и класс, и что угодно ещё — суть от этого не изменится, от необходимости получения функции из её имени не отвертеться.

T>А ты здесь не ошибешься ли?


Я никогда не исключаю такой возможности. С удовольствием посмотрел бы на пример.

А>> Я сомневаюсь, что по одной этой частной и до предела упрощённой задаче можно понять область применимости рефлексии для метапрограммирования на TH. Никакой зашкаливающий IQ не поможет.


T>Мой IQ вполне способен.


Что, все-все возможные применения можешь придумать? Не верю. Если уж даже я не могу...

T>>>А так — да, не могу.

А>> Об этом и речь. И я не могу. Но хочу.

T>Лично я, обычно, хочу решить задачу, а не решить задачу определённым образом.


Задача — сделать Лисп из Хаскелля пользуясь метапрограммированием. Из Лиспа Хаскелль таким образом сделать можно, теперь интересно посмотреть и на обратное преобразование. Задача, конечно же, игрушечная и практического смысла в ней мало, но многие реальные задачи сводятся к чему-то очень похожему.

T>Собственно, моё напоминание об отсутствии решения было как раз для напоминания о том, что идиоматическое решение на Хаскеле отлично от идиоматического решения в стиле Лиспа, с метапрограммированием и прочей рефлексией.


Мне в данном случае интересно исключительно решение с метапрограммированием. Интерпретатор на комбинаторах, или генерацию кода, сделать можно всегда, и это не интересно.

А>> А вот мне — надо. Судя по убожеству всех мною виденных примеров применения TH, другим не то что "не надо", а просто не задумывался никто о подобных вещах. Потому и пробелы в API.


T>А почему не задумывались, не задумывался?


Инерция мышления. Я за это и не люблю "идиоматические решения" — глаз замыливают. Самое интересное всегда вылезает из пограничных областей, из неожиданного применения технологий.

T>Быть может, хватает обычного Хаскеля? Быть может, твоя формулировка решения ненадёжна или невыгодна?


В том то и дело, что она вполне надёжна и выгодна. Типобезопасность не нарушается, метапрограммирование всё равно уже есть и никуда не денется — так что ж мешает сделать его полноценным и использовать на всю катушку?

А>> Очень частая ситуация, в моей практике гораздо чаще смешанный режим исполнения встречается, чем чистая компиляция или чистая интерпретация.


T>А что за область деятельности?


Собственно, всё, связанное с языками — как DSL, так и общего назначения. Rule-based systems, CAD-ы, static code analysis с программируемыми правилами, и т.д.

T>Этого можно достичь кодогенерацией.


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

T>Можно ли добиться требуемого тебе результат, если подняться на ещё один уровень в вызовах Template Haskell?


Мне кажется, что не стоит так делать. Это должно быть прозрачно для пользователя. Использует код макры, не использует код макры — это не имеет значения. Тем более что макра может раскрываться в конструкцию, использующую другие макры.

T>Поможет ли такой вариант? Ведь в processModuleDefs мы можем собрать всю нужную нам информацию и добавить специальную функцию для обращения к ней.


Это чрезмерное усложнение. В нашей игрушечной задаче, например, это потребует изменения самого DSL (Лиспа, то есть). Что само по себе уже подозрительно — ведь хотелось бы иметь возможность реализовать любой DSL.

А>> Если это EDSL? Препроцессоры городить — это позорная сиплюсплюсщина. Метапрограммирование на то и нужно, чтоб без препроцессоров обходиться.


T>Комбинаторы?


А если синтаксис Хаскелля не нужен, а нужен совсем другой? А если производительности такой интерпретации не хватает? А если кроме родной Хаскелевой системы типов хочется ещё своих сложных проверок добавить?

T>Как много комбинаторных библиотек ты написал?


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

T>Тем меньше развитие.


Согласен, это обратная сторона медали.

T>С развитием маленькие группы людей не справляются. Даже с развитием естественных языков, что говорить о менее повседневных вещах.


Вот и ворую идеи у сообществ лиспа, немерла, Хаскелля, Axiom и десятков других. Ничего не отдавая им за это.

T>К тому же метапрограммирование само по себе не имеет ценности. Оно имеет ценность в качестве одного из инструментов.


Именно. Но надо знать, как инструментом пользоваться. И это знание имеет ценность.

T>Если оно действительно настолько мощно и настолько применимо (и безопасно и просто в использовании, это важно), то предъявить пример не составило бы труда.


Ок. Покажу пример, несколько позже — надо подобрать то, что на комбинаторах было бы особенно уродливым и трудоёмким. В принципе — даже этот лисп на TH — вполне себе пример, поскольку интерпретатор с аналогичными свойствами сделать намного сложнее.

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


Я не настолько альтруистичен. Но так уж и быть, в этом случае нарушу свои правила.

T>Для этого уже тип не нужен (не может быть двух определений с разными типами в одном модуле). Список используемых модулей нужен, но и всё.


Тип нужен, чтобы это определение применить.

T>А его, этот список модулей, можно получить, поднявшись на уровень выше, как я вверху предложил. Надо пройти по всем Name и взять у них модули.


Увы, увы, это ещё не решение. Попробую пропатчить ghc и показать то минимальное изменение, которого достаточно для этой фичи.

T>Наверное.


T>Вот, например:


Так... Надо подумать. Пока не вижу, как бы это мне помогло.

T>(бляха муха, я даже чуток понял Data.Generics в процессе! вот она, польза приведения примеров


Это так, я тоже кой чего полезного понял, пока лисп на TH делал.

T>В общем и целом, я думаю, что Лисп-в-стиле-Лиспа на Хаскеле не получится.


А почему бы и нет? Ведь ничего же не мешает, теоретически.

T>Потому, что API TH под это не заточено. Оно заточено под другие дела.


Какие же?

T>Помниться, мне макросов хотелось недели две, пока до функций высшего порядка не дошёл.


Мне никакие функции высшего порядка макросы не заменят. Слишком много интересных применений для макросов я нашел.

А>> Да, я не исключаю, что может найтись какое-то решение. Но вообще с продуманностью API у TH серьёзные проблемы.


T>Я так не думаю.


T>Над ним работали мощнейшие умы планеты Земля.


Они явно от этой проблемы просто отмахнулись.

Я когда-то уже обсуждал с SPJ статическое метапрограммирование — так тогда он вообще не понимал, для чего оно может быть нужно в Хаскелле, и не знал, что с ним делают в Лиспе. Потом мнение поменял, но до просветления явно ещё пару шагов требуется. Инерция мышления, однако.
Re[26]: Как написать виртуальную машину на LISP
От: thesz Россия http://thesz.livejournal.com
Дата: 18.08.09 20:14
Оценка:
Здравствуйте, Аноним, Вы писали:

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


А>>>>> В этой конкретной задаче — нет смысла. API фиксированное, я ничего с ним сделать не могу.

T>>>>Ну, кое-что мне подсказывает, что "нет смысла" в твоих устах не много значит.
А>>> Ну и как я могу изменить определение монады Quasi, не пересобирая ghc?
T>>А это-то здесь причём?
А> При том, что мы говорим о вполне конкретном случае применения рефлексии — внутри сплайса, для приложения поименованной функции из другого модуля с известной сигнатурой типа. То есть, о работе с API собственно GHC.

Не, ничего такого.

Мы говорим о реализации компилятора Лиспа в виде DSEL на Хаскеле.

Один из вариантов этой реализации — через Template Haskell.

Поэтому не надо зацикливаться. И поэтому — а почему бы не попробовать ассоциированные типы и классы типов?

T>>Может, для решения хватит ассоциированных типов и типов классов?

А> Не вижу такого решения. Ещё раз повторю формулировку задачи — есть код, сгенерённый внутри сплайса в каком-то другом модуле — функция "macro_blahblahblah", в которую было откомпилированно определение defmacro. Есть распарсенный лисповский список, голова которого — символ "blahblahblah". Надо получить результат приложения функции macro_blahblahblah :: LispV -> LispV к остатку этого списка. Конечно кроме функции можно генерить и тип, и класс, и что угодно ещё — суть от этого не изменится, от необходимости получения функции из её имени не отвертеться.

Так надо попробовать, нет?

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

T>>А ты здесь не ошибешься ли?

А> Я никогда не исключаю такой возможности. С удовольствием посмотрел бы на пример.

Всё дело в том, что я в Лиспах не разбираюсь.

Почему бы тебе не попробовать выразить свою задачу с типами?

А>>> Я сомневаюсь, что по одной этой частной и до предела упрощённой задаче можно понять область применимости рефлексии для метапрограммирования на TH. Никакой зашкаливающий IQ не поможет.

T>>Мой IQ вполне способен.
А> Что, все-все возможные применения можешь придумать? Не верю. Если уж даже я не могу...

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

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

T>>>>А так — да, не могу.

А>>> Об этом и речь. И я не могу. Но хочу.
T>>Лично я, обычно, хочу решить задачу, а не решить задачу определённым образом.
А> Задача — сделать Лисп из Хаскелля пользуясь метапрограммированием.

Замечу, что в нынешнем Хаскеле TH это всего лишь один из вариантов метапрограммирования.

А> Из Лиспа Хаскелль таким образом сделать можно, теперь интересно посмотреть и на обратное преобразование.


I'd like to see that feat.

А> Задача, конечно же, игрушечная и практического смысла в ней мало, но многие реальные задачи сводятся к чему-то очень похожему.


И решаются ассоциированными типами и типами классов.

T>>Собственно, моё напоминание об отсутствии решения было как раз для напоминания о том, что идиоматическое решение на Хаскеле отлично от идиоматического решения в стиле Лиспа, с метапрограммированием и прочей рефлексией.

А> Мне в данном случае интересно исключительно решение с метапрограммированием. Интерпретатор на комбинаторах, или генерацию кода, сделать можно всегда, и это не интересно.

Я не вижу выигрыша в этом. Это получается не решение задачи, приближённое к реальному, а решение задачи с дополнительными условиями. Кому как, а мне неинтересно.

Так, побазарить.

А>>> А вот мне — надо. Судя по убожеству всех мною виденных примеров применения TH, другим не то что "не надо", а просто не задумывался никто о подобных вещах. Потому и пробелы в API.

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

Это "интересное" интересно только программисту, а не пользователю.

T>>Быть может, хватает обычного Хаскеля? Быть может, твоя формулировка решения ненадёжна или невыгодна?

А> В том то и дело, что она вполне надёжна и выгодна. Типобезопасность не нарушается, метапрограммирование всё равно уже есть и никуда не денется — так что ж мешает сделать его полноценным и использовать на всю катушку?

Да зачем?

Я использую Хаскель в течении уже 11 лет, из них четыре года в повседневной работе.

Мне метапрограммирование было нужно только первые две недели этих 11 лет и ещё один раз когда-то недавно. А уж DSL да DSEL я понаписал немало.

Сейчас собрался использовать TH. Но у меня задача как раз и состоит в преобразовании кода по правилам.

А>>> Очень частая ситуация, в моей практике гораздо чаще смешанный режим исполнения встречается, чем чистая компиляция или чистая интерпретация.

T>>А что за область деятельности?
А> Собственно, всё, связанное с языками — как DSL, так и общего назначения. Rule-based systems, CAD-ы, static code analysis с программируемыми правилами, и т.д.

Здесь бы я либо просто компилировал комбинаторы, либо генерировал код.

T>>Этого можно достичь кодогенерацией.

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

Значит, надо генерировать типобезопасный ЯП, например, Хаскель.

T>>Можно ли добиться требуемого тебе результат, если подняться на ещё один уровень в вызовах Template Haskell?


А> Мне кажется, что не стоит так делать. Это должно быть прозрачно для пользователя. Использует код макры, не использует код макры — это не имеет значения. Тем более что макра может раскрываться в конструкцию, использующую другие макры.


Здесь либо сплайсы, либо не сплайсы.

Поэтому либо будут $(func ...), либо из не будет. Последнее доступно только с помощью ассоциированных типов и классов типов.

Вот этот параграф твоего комментария навевает на меня грустные мысли: ты хочешь добиться чего-то с искусственными ограничениями. С одной стороны, ты желаешь получить "прозрачный для пользователя" код, с другой стороны ты не желаешь вкладывать в цитирование (splice) весь модуль (а при этом получается возможность так сделать).

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

Ну, успехов.

T>>Поможет ли такой вариант? Ведь в processModuleDefs мы можем собрать всю нужную нам информацию и добавить специальную функцию для обращения к ней.

А> Это чрезмерное усложнение. В нашей игрушечной задаче, например, это потребует изменения самого DSL (Лиспа, то есть). Что само по себе уже подозрительно — ведь хотелось бы иметь возможность реализовать любой DSL.

Приведи пример кода, которого ты хочешь добиться.

А>>> Если это EDSL? Препроцессоры городить — это позорная сиплюсплюсщина. Метапрограммирование на то и нужно, чтоб без препроцессоров обходиться.

T>>Комбинаторы?
А> А если синтаксис Хаскелля не нужен, а нужен совсем другой?

Внешний синтаксис через комбинаторы?

А> А если производительности такой интерпретации не хватает?


par/pseq для распараллеливания?

А> А если кроме родной Хаскелевой системы типов хочется ещё своих сложных проверок добавить?


Внешний DSL?

А что за проверки, приведи пример.

T>>Как много комбинаторных библиотек ты написал?

А> До хрена. Например, тот же packrat я делал и на комбинаторах, и метапрограммированием. Второй вариант быстрее ну очень заметно, и при этом позволяет пользоваться приличным синтаксисом.

Задам вопрос по-другому: писал ли ты комбинаторную библиотеку на Хаскеле с использованием {-# INLINE #-} и {-# RULES #-}?

T>>Тем меньше развитие.

А> Согласен, это обратная сторона медали.

T>>С развитием маленькие группы людей не справляются. Даже с развитием естественных языков, что говорить о менее повседневных вещах.

А> Вот и ворую идеи у сообществ лиспа, немерла, Хаскелля, Axiom и десятков других. Ничего не отдавая им за это.

Это ты так думаешь.

T>>К тому же метапрограммирование само по себе не имеет ценности. Оно имеет ценность в качестве одного из инструментов.

А> Именно. Но надо знать, как инструментом пользоваться. И это знание имеет ценность.

Это даже не очень и смешно. Зачем кому-то знание о том, как пользоваться не очень ценным (из-за отсутствия развития) инструментом?

T>>Если оно действительно настолько мощно и настолько применимо (и безопасно и просто в использовании, это важно), то предъявить пример не составило бы труда.

А> Ок. Покажу пример, несколько позже — надо подобрать то, что на комбинаторах было бы особенно уродливым и трудоёмким. В принципе — даже этот лисп на TH — вполне себе пример, поскольку интерпретатор с аналогичными свойствами сделать намного сложнее.

Какие же свойства должны быть "аналогичны"?

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

А> Я не настолько альтруистичен. Но так уж и быть, в этом случае нарушу свои правила.

Уверяю тебя, я всё и всегда делаю ради собственной выгоды.

T>>Для этого уже тип не нужен (не может быть двух определений с разными типами в одном модуле). Список используемых модулей нужен, но и всё.

А> Тип нужен, чтобы это определение применить.

Тогда — ассоциированные типы.

T>>А его, этот список модулей, можно получить, поднявшись на уровень выше, как я вверху предложил. Надо пройти по всем Name и взять у них модули.

А> Увы, увы, это ещё не решение. Попробую пропатчить ghc и показать то минимальное изменение, которого достаточно для этой фичи.

Посмотрел на твоё решение повнимательней. Я не думаю, что тебе надо вызывать какую-либо функцию.

BTW, есть удобные quasi-quotes:
[$quoter|quoted text|]

--например:
[$thlisp|(begin .... print ....)|]


T>>В общем и целом, я думаю, что Лисп-в-стиле-Лиспа на Хаскеле не получится.

А> А почему бы и нет? Ведь ничего же не мешает, теоретически.

Не с синтаксисом Лиспа. Без него — получится.

T>>Потому, что API TH под это не заточено. Оно заточено под другие дела.

А> Какие же?

Например, foreign генерировать. Всякого рода instance создавать.

Что еще...

Текст слегка видоизменять, я думаю. Делать [i]небольшие{/i] языки.

T>>Помниться, мне макросов хотелось недели две, пока до функций высшего порядка не дошёл.

А> Мне никакие функции высшего порядка макросы не заменят. Слишком много интересных применений для макросов я нашел.

Это всё от преждевременной оптимизации.

А>>> Да, я не исключаю, что может найтись какое-то решение. Но вообще с продуманностью API у TH серьёзные проблемы.

T>>Я так не думаю.
T>>Над ним работали мощнейшие умы планеты Земля.
А> Они явно от этой проблемы просто отмахнулись.

А почему?

А> Я когда-то уже обсуждал с SPJ статическое метапрограммирование — так тогда он вообще не понимал, для чего оно может быть нужно в Хаскелле, и не знал, что с ним делают в Лиспе. Потом мнение поменял, но до просветления явно ещё пару шагов требуется. Инерция мышления, однако.


Так то, что с ним делают в Лиспе — получают скорость выполнения, — делают в Хаскеле с помощью оптимизаций.

Которые оптимизации — как в примере с теми же самыми генериками выше по теме в дискуссии с lomeo, — могут быть применимы где-то ещё, не только в каком-то определённом месте.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[27]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 19.08.09 09:02
Оценка:
Здравствуйте, thesz, Вы писали:

А>> При том, что мы говорим о вполне конкретном случае применения рефлексии — внутри сплайса, для приложения поименованной функции из другого модуля с известной сигнатурой типа. То есть, о работе с API собственно GHC.


T>Не, ничего такого.


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

T>Мы говорим о реализации компилятора Лиспа в виде DSEL на Хаскеле.


В виде компилируемого EDSL на Хаскеле с произвольным синтаксисом.

T>Один из вариантов этой реализации — через Template Haskell.


Все другие чрезмерно перанальны.

T>Поэтому не надо зацикливаться. И поэтому — а почему бы не попробовать ассоциированные типы и классы типов?


Потому, что есть условия:
— синтаксис EDSL произволен — ну да ладно, никто не запрещает раскрывать сплайс в код на комбинаторах, это не проблема
— он должен компилироваться в Хаскелль
— должно быть реализовано метапрограммирование в eDSL. Почему? Так хочет заказчик, и не колышет. В спецификации языка есть defmacro — вынь да положь defmacro в реализации.
— общий контекст с хост-языком (решене из п.1. тут тоже подходит)

Ну и в конце концов — это наиболее общее решение. Любые другие будут являться частным случаем этого подхода.

T>Так надо попробовать, нет?


Не вижу пути.

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


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

T>>>А ты здесь не ошибешься ли?

А>> Я никогда не исключаю такой возможности. С удовольствием посмотрел бы на пример.

T>Всё дело в том, что я в Лиспах не разбираюсь.


А зря. В этом и разница — я разбираюсь во всём — и в Лиспах, и в Хаскелле, и во всяких там APL-ах и прочих J, и вообще во всём, что только есть. И могу выбирать решения из разных миров. А в субкультуре Хаскелля сложились определённые подходы, от которых народ очень не любит отходить.

T>Почему бы тебе не попробовать выразить свою задачу с типами?


Почему ты думаешь, что я не пробовал?

А>>>> Я сомневаюсь, что по одной этой частной и до предела упрощённой задаче можно понять область применимости рефлексии для метапрограммирования на TH. Никакой зашкаливающий IQ не поможет.

T>>>Мой IQ вполне способен.
А>> Что, все-все возможные применения можешь придумать? Не верю. Если уж даже я не могу...

T>Ты ещё ни разу не хвастался ни в этой теме, ни в какой-либо другой своим IQ.


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

T> К тому же ты анонимен и мы вольны выбирать из сообщений анонимов на РСДН те, что намерены приписать тебе, а также мы вольны отбрасывать те сообщения, что считаем несущественными.


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

А>> Задача — сделать Лисп из Хаскелля пользуясь метапрограммированием.


T>Замечу, что в нынешнем Хаскеле TH это всего лишь один из вариантов метапрограммирования.


Единственный, позволяющий отойти от синтаксиса Хаскелля.

А>> Из Лиспа Хаскелль таким образом сделать можно, теперь интересно посмотреть и на обратное преобразование.


T>I'd like to see that feat.


В смысле — Хаскелль на Лиспе?

А>> Задача, конечно же, игрушечная и практического смысла в ней мало, но многие реальные задачи сводятся к чему-то очень похожему.


T>И решаются ассоциированными типами и типами классов.


Не решаются. Важное условие — доступ ко всем определениям во время компиляции.

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


T>Это "интересное" интересно только программисту, а не пользователю.


Это как раз программисту интересно, чтоб его система типов по рукам била. А пользователю интересно, чтоб всё работало, и чтоб было сделано в срок. А для этого все средства хороши.

T>Да зачем?


T>Я использую Хаскель в течении уже 11 лет, из них четыре года в повседневной работе.


T>Мне метапрограммирование было нужно только первые две недели этих 11 лет и ещё один раз когда-то недавно. А уж DSL да DSEL я понаписал немало.


Не отмазка. Я знаю лисперов, которые лет тридцать на Лиспе пишут, и до сих пор не умеют пользоваться как следует метапрограммированием.

Я уж не говорю о тех, кто тридцать лет пишет на Фортране, и не умеет пользоваться вообще ничем. Я сам — функциональщик с пятнадцатилетним стажем, но метапрограммированием пользуюсь (кстати, преимущественно в реальных, практических задачах) лишь последние лет шесть.

T>Сейчас собрался использовать TH. Но у меня задача как раз и состоит в преобразовании кода по правилам.


Любая компиляция — это "преобразование кода по правилам".

А>> Собственно, всё, связанное с языками — как DSL, так и общего назначения. Rule-based systems, CAD-ы, static code analysis с программируемыми правилами, и т.д.


T>Здесь бы я либо просто компилировал комбинаторы, либо генерировал код.


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

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


T>Значит, надо генерировать типобезопасный ЯП, например, Хаскель.


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


T>Поэтому либо будут $(func ...), либо из не будет. Последнее доступно только с помощью ассоциированных типов и классов типов.


Дались тебе эти ассоциированные типы...

T> Вот этот параграф твоего комментария навевает на меня грустные мысли: ты хочешь добиться чего-то с искусственными ограничениями.


Это не ограничения. Ограничения — это то, что накладывает на меня Хаскелль. И в этом случае — совершенно безосновательно накладывает. А я вообще не люблю ограничения.

T> С одной стороны, ты желаешь получить "прозрачный для пользователя" код, с другой стороны ты не желаешь вкладывать в цитирование (splice) весь модуль (а при этом получается возможность так сделать).


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

T> Получается, что ты просто упёрся в достижении тобой понимаемой цели через метапрограммирование, как его понимаешь ты.


У меня есть на это причины — иерархическое метапрограммирование. Другими способами его реализовать нельзя.

А>> Это чрезмерное усложнение. В нашей игрушечной задаче, например, это потребует изменения самого DSL (Лиспа, то есть). Что само по себе уже подозрительно — ведь хотелось бы иметь возможность реализовать любой DSL.


T>Приведи пример кода, которого ты хочешь добиться.


Грубо говоря, в одном модуле определяем

$(thlisptop "(defmacro list args (match args ((head . tail) `(cons ,head (list ,@tail))) (() 'nil)))")

а в другом уже можем макрой воспользоваться:

$(thlisp "(map (lambda (x) (* x x)) (list 1 2 3 4))")

А>>>> Если это EDSL? Препроцессоры городить — это позорная сиплюсплюсщина. Метапрограммирование на то и нужно, чтоб без препроцессоров обходиться.

T>>>Комбинаторы?
А>> А если синтаксис Хаскелля не нужен, а нужен совсем другой?

T>Внешний синтаксис через комбинаторы?


Да какой он к бесам внешний. Не, я понимаю, можно извратиться, поднапрячься, и даже что-то похожее на бейсик изобразить — но это именно что извращение. Несистемное решение. Я же ещё не сказал, что к этим eDSL нужна полноценная поддержка от IDE, со всякими там intellisense и прочей ерундой.

А>> А если производительности такой интерпретации не хватает?


T>par/pseq для распараллеливания?


Не смешно даже.

А>> А если кроме родной Хаскелевой системы типов хочется ещё своих сложных проверок добавить?


T>Внешний DSL?


Не вижу существенных отличий в методах реализации внешних DSL от встраиваемых.

T>А что за проверки, приведи пример.


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

T>>>Как много комбинаторных библиотек ты написал?

А>> До хрена. Например, тот же packrat я делал и на комбинаторах, и метапрограммированием. Второй вариант быстрее ну очень заметно, и при этом позволяет пользоваться приличным синтаксисом.

T>Задам вопрос по-другому: писал ли ты комбинаторную библиотеку на Хаскеле с использованием {-# INLINE #-} и {-# RULES #-}?


Не вижу, чем оно помогло бы в реализации того же Packrat. Я использовал {-# SPECIALIZE ... #- }

T>>>С развитием маленькие группы людей не справляются. Даже с развитием естественных языков, что говорить о менее повседневных вещах.

А>> Вот и ворую идеи у сообществ лиспа, немерла, Хаскелля, Axiom и десятков других. Ничего не отдавая им за это.

T>Это ты так думаешь.


Думаю, что ворую? Да нет, знаю, что ворую — вон, работает всё в конкретных проектах, каши не просит. Мне хорошо, а немерлисты о факте воровства даже и не в курсе.

T>>>К тому же метапрограммирование само по себе не имеет ценности. Оно имеет ценность в качестве одного из инструментов.

А>> Именно. Но надо знать, как инструментом пользоваться. И это знание имеет ценность.

T>Это даже не очень и смешно. Зачем кому-то знание о том, как пользоваться не очень ценным (из-за отсутствия развития) инструментом?


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

А>> Ок. Покажу пример, несколько позже — надо подобрать то, что на комбинаторах было бы особенно уродливым и трудоёмким. В принципе — даже этот лисп на TH — вполне себе пример, поскольку интерпретатор с аналогичными свойствами сделать намного сложнее.


T>Какие же свойства должны быть "аналогичны"?


Общее с Хаскеллем пространство имён, eager семантика исполнения, произвольный синтаксис, раскрытие макр во время компиляции.

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

А>> Я не настолько альтруистичен. Но так уж и быть, в этом случае нарушу свои правила.

T>Уверяю тебя, я всё и всегда делаю ради собственной выгоды.


В чём персональная выгода от пропаганды Хаскелля? Кому надо — и так все давно в курсе.

Моя выгода от этой дискуссии очевидна — я могу или найти решение в рамках заданных условий, или убедиться, что его нет. Экономия времени, однако.

T>>>Для этого уже тип не нужен (не может быть двух определений с разными типами в одном модуле). Список используемых модулей нужен, но и всё.

А>> Тип нужен, чтобы это определение применить.

T>Тогда — ассоциированные типы.


Как это мне поможет динамически вытащить определение по его имени?

T>>>А его, этот список модулей, можно получить, поднявшись на уровень выше, как я вверху предложил. Надо пройти по всем Name и взять у них модули.

А>> Увы, увы, это ещё не решение. Попробую пропатчить ghc и показать то минимальное изменение, которого достаточно для этой фичи.

T>Посмотрел на твоё решение повнимательней. Я не думаю, что тебе надо вызывать какую-либо функцию.


Ты не понимаешь Лиспа, совершенно. И по этому примеру тем более не сможешь понять, где там надо впихнуть макры.

T>BTW, есть удобные quasi-quotes:

T>
[$quoter|quoted text|]

T>--например:
T>[$thlisp|(begin .... print ....)|]
T>


В данном случае толку от них никакого — что кавычки, что палочки, один хрен. Был бы у Хаскелля парсер на PEG — другое дело, можно было бы органично встраивать в него любой синтаксис.

T>>>В общем и целом, я думаю, что Лисп-в-стиле-Лиспа на Хаскеле не получится.

А>> А почему бы и нет? Ведь ничего же не мешает, теоретически.

T>Не с синтаксисом Лиспа. Без него — получится.


Без него не интересно. Лисп в данном случае — частный пример. Я хочу использовать абсолютно произвольный синтаксис.

T>>>Потому, что API TH под это не заточено. Оно заточено под другие дела.

А>> Какие же?

T>Например, foreign генерировать. Всякого рода instance создавать.


Примитивщина.

T>Что еще...


T>Текст слегка видоизменять, я думаю. Делать [i]небольшие{/i] языки.


А небольшие языки проще всего делать итерационным надстраиванием над языками побольше. Мне нужно иерархическое метапрограммирование, а не просто "foreign генерить".

T>>>Помниться, мне макросов хотелось недели две, пока до функций высшего порядка не дошёл.

А>> Мне никакие функции высшего порядка макросы не заменят. Слишком много интересных применений для макросов я нашел.

T>Это всё от преждевременной оптимизации.


Нет, оптимизация в данном случае совершенно не при чём. Важна семантика.

А>> Они явно от этой проблемы просто отмахнулись.


T>А почему?


По причине непонимания последствий.

А>> Я когда-то уже обсуждал с SPJ статическое метапрограммирование — так тогда он вообще не понимал, для чего оно может быть нужно в Хаскелле, и не знал, что с ним делают в Лиспе. Потом мнение поменял, но до просветления явно ещё пару шагов требуется. Инерция мышления, однако.


T>Так то, что с ним делают в Лиспе — получают скорость выполнения, — делают в Хаскеле с помощью оптимизаций.


Нет, то, что с ним делают в Лиспе, в Хаскелле не делают вообще.

T>Которые оптимизации — как в примере с теми же самыми генериками выше по теме в дискуссии с lomeo, — могут быть применимы где-то ещё, не только в каком-то определённом месте.


Кстати да, ast:visit таки очень неплохой пример преимуществ метапрограммирования.
Re[28]: Как написать виртуальную машину на LISP
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 19.08.09 11:33
Оценка:
Здравствуйте, Аноним, Вы писали:

T>>Замечу, что в нынешнем Хаскеле TH это всего лишь один из вариантов метапрограммирования.

А> Единственный, позволяющий отойти от синтаксиса Хаскелля.

Просто, чтобы докопаться вспомню о препроцессорах

А> Не решаются. Важное условие — доступ ко всем определениям во время компиляции.


Ограничение TH — определение, сгенеренное в каком нибудь модуле, в этом модуле не видно.

А>Грубо говоря, в одном модуле определяем

А>$(thlisptop "(defmacro list args (match args ((head . tail) `(cons ,head (list ,@tail))) (() 'nil)))")
А> а в другом уже можем макрой воспользоваться:
А>$(thlisp "(map (lambda (x) (* x x)) (list 1 2 3 4))")

А в чём проблема?

thlisptop (defmacro...) создаёт определение функции list, которую мы можем использовать в другом модуле, неважно в сплайсах или нет.

Или я чего то не вижу?
Re[29]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 19.08.09 11:47
Оценка:
Здравствуйте, lomeo, Вы писали:

L>Просто, чтобы докопаться вспомню о препроцессорах


Не годится.

А>> Не решаются. Важное условие — доступ ко всем определениям во время компиляции.


L>Ограничение TH — определение, сгенеренное в каком нибудь модуле, в этом модуле не видно.


С этим ограничением я ещё готов мириться. У Nemerle тоже аналогичные ограничения есть. Мне мешает невозможность во время компиляции вызвать функцию с известным именем.

L>А в чём проблема?


L>thlisptop (defmacro...) создаёт определение функции list, которую мы можем использовать в другом модуле, неважно в сплайсах или нет.


Эту функцию надо использовать во время компиляции. Чтобы потом сплайс вернул код, скомпилированный из того кода, который вернёт эта функция. Это же макра, а не просто функция. Во время разворачивания содержимого сплайса мы про list знаем только имя "list".

L>Или я чего то не вижу?


Конкретного решения не видишь. Потому что его нет.
Re[30]: Как написать виртуальную машину на LISP
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 19.08.09 11:51
Оценка:
Здравствуйте, Аноним, Вы писали:

А> Эту функцию надо использовать во время компиляции. Чтобы потом сплайс вернул код, скомпилированный из того кода, который вернёт эта функция. Это же макра, а не просто функция. Во время разворачивания содержимого сплайса мы про list знаем только имя "list".


Ну да, во время компиляции макра и срабатывает.
Имеем просто "list", получаем

listMacro = varE (mkName "list")

и запускаем его внутри

$( [| ... $listMacro ... |] )

Всё замечательно работает.

L>>Или я чего то не вижу?

А> Конкретного решения не видишь. Потому что его нет.

Не пойму
Re[31]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 19.08.09 11:58
Оценка:
Здравствуйте, lomeo, Вы писали:

L>Здравствуйте, Аноним, Вы писали:


А>> Эту функцию надо использовать во время компиляции. Чтобы потом сплайс вернул код, скомпилированный из того кода, который вернёт эта функция. Это же макра, а не просто функция. Во время разворачивания содержимого сплайса мы про list знаем только имя "list".


L>Ну да, во время компиляции макра и срабатывает.


Как, конкретно? Напиши кусок кода для функции expand_macros :: LispV -> Q LispV

Сделать распознавание глобальных функций, переменных и макр с помощью reify там можно легко. Не ясно, как функции и переменные оставлять, а макры раскрывать на месте (причём, результат развёртки макры может содержать другие макры, даже не может, а должен).

L>Имеем просто "list", получаем


L>listMacro = varE (mkName "list")


А вот этого нам на фиг не надо. list надо применить во время развёртки сплайса и забыть о нём. В конечный код пойдёт вовсе не (list 1 2 3), а
(cons 1 (cons 2 (cons 3 nil))), точнее, результат компиляции этой конструкции в Хаскелль. Никаких "list" там быть не может и не должно — это не функция, это макра. Точно так же в конечном коде не будет никаких "thlisptop" и прочих макр.

L>и запускаем его внутри


L>$( [| ... $listMacro ... |] )


L>Всё замечательно работает.


В таком варианте — вообще никак не работает.
Re[32]: Как написать виртуальную машину на LISP
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 19.08.09 12:17
Оценка:
Здравствуйте, Аноним, Вы писали:

L>>Всё замечательно работает.

А> В таком варианте — вообще никак не работает.

Так! Давай я expand macro писать не буду, а напишу декоративный пример, и ты мне покажешь, где именно проблема, ок?

Тут у нас файл Macro.hs, в котором определён макрос list (это не он, но нам важен же вызов при компиляции, а не что он делает, так?)

module Macro where

import Language.Haskell.TH

$( [d| list = id |] ) -- как будто мы его сгенерировали с помощью thlisptop


А вот файл Main.hs, который использует list во время компиляции (т.е. рантайм list зваться не будет)

import Macro
import Language.Haskell.TH

o_O = 42

main = print $( [| $(varE (mkName "list")) o_O |] )


Т.е. $(varE (mkName "list")) даёт нам list, [| |] даёт нам выражение list o_O, а внешний $() вызывает его компайл-тайм.

Чего я не вижу?
Re[33]: Как написать виртуальную машину на LISP
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 19.08.09 12:23
Оценка:
Здравствуйте, lomeo, Вы писали:

L>Т.е. $(varE (mkName "list")) даёт нам list, [| |] даёт нам выражение list o_O, а внешний $() вызывает его компайл-тайм.


Я гоню, пора в отпуск
Re[33]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 19.08.09 12:26
Оценка:
Здравствуйте, lomeo, Вы писали:

L>
main = print $( [| $(varE (mkName "list")) o_O |] )


L>Т.е. $(varE (mkName "list")) даёт нам list, [| |] даёт нам выражение list o_O, а внешний $() вызывает его компайл-тайм.


Не вызовет он никакой list во время компиляции. Он его тупо подставит.

L>Чего я не вижу?


Того, что это выражение будет скомпилировано в код:
main = print (list o_O)
Re[34]: Как написать виртуальную машину на LISP
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 19.08.09 13:10
Оценка:
Здравствуйте, Аноним, Вы писали:

А> Того, что это выражение будет скомпилировано в код:

А>
А>main = print (list o_O)
А>


Я понял — проблема — в получении функции по имени и тут же по месту её вызова. Может быть стоит попробовать решение а-ля hs-plugins?
Или при создании макроса регистрировать её в некой глобальной переменной по имени и тогда можно будет просто получить её?
Re[35]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 19.08.09 13:44
Оценка:
Здравствуйте, lomeo, Вы писали:

L>Я понял — проблема — в получении функции по имени и тут же по месту её вызова.


Да, именно так.

L> Может быть стоит попробовать решение а-ля hs-plugins?


Это хак будет.

L>Или при создании макроса регистрировать её в некой глобальной переменной по имени и тогда можно будет просто получить её?


Конечно же так можно — но это уже совершенно неправославно, о чём я тут, собственно, и сокрушаюсь. Просто я недоумеваю — reify есть и считается православным, runMeta внутри есть, и реализовано вполне православно — что ж его не дать простому смертному пользователю подёргать точно так же, как reify?
Re[36]: Как написать виртуальную машину на LISP
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 19.08.09 14:05
Оценка:
Здравствуйте, Аноним, Вы писали:

А> Конечно же так можно — но это уже совершенно неправославно, о чём я тут, собственно, и сокрушаюсь. Просто я недоумеваю — reify есть и считается православным, runMeta внутри есть, и реализовано вполне православно — что ж его не дать простому смертному пользователю подёргать точно так же, как reify?


Угу, обидно. В лиспе программы, которые пишут программы, которые пишут программы...
А в Хаскель только программы, которые пишут программы.

В общем я почитал, уровень можно поднять только из другого модуля (нет вложенных сплайсов), т.е. кошерного способа сделать это через TH нет.
Re[30]: Как написать виртуальную машину на LISP
От: awson  
Дата: 19.08.09 22:12
Оценка: 1 (1)
Здравствуйте, Аноним, Вы писали:

А> Эту функцию надо использовать во время компиляции. Чтобы потом сплайс вернул код, скомпилированный из того кода, который вернёт эта функция. Это же макра, а не просто функция. Во время разворачивания содержимого сплайса мы про list знаем только имя "list".


Не нужно фантазировать. Хотя кое-что изменилось со времен написания основного документа — принципы остались на месте. В частности, оттуда можно почерпнуть знание о том, что существенная часть ограничений (включающая все, которые вы ищете способ преодолеть) образовалась не по недоразумению, а вполне себе by design. Эта мысль проходит буквально красной нитью через весь текст, но особенно выпукло обозначена на стр. 6 указанного документа в разделе 7 — "Typing Template Haskell". Поэтому большинство способов их преодоления являются "хаками" тривиально. Если собираетесь упорствовать (и, следовательно, мириться с хаками) — посмотрите, что делает Matt Morrow — http://moonpatio.com/repos, http://code.haskell.org/~morrow. Кстати, для реализации затеи во всей, так сказать, красе ему приходится использовать (как ниже и предположил lomeo) — plugins, а именно, дубину eval оттуда.

И еще. Регулярное вещание анонимом обозначает как минимум неуважение к аудитории. thesz уже намекал на это, однако, даже если Вы и не идентифицируете себя как адресата его намека, я напоминаю, что насчет анонимов в сети существует практически консенсус.
Re[31]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 20.08.09 08:48
Оценка:
Здравствуйте, awson, Вы писали:

A>Не нужно фантазировать. Хотя кое-что изменилось со времен написания основного документа — принципы остались на месте.


Я как раз и утверждаю, что разработчики концепции просто не понимают принципов метапрограммирования.

A> В частности, оттуда можно почерпнуть знание о том, что существенная часть ограничений (включающая все, которые вы ищете способ преодолеть) образовалась не по недоразумению, а вполне себе by design.


И это просиходит исключительно от полного непонимания смысла метапрограммирования.

A> Эта мысль проходит буквально красной нитью через весь текст, но особенно выпукло обозначена на стр. 6 указанного документа в разделе 7 — "Typing Template Haskell".


Я, как мне казалось, совершенно доходчиво объяснил, почему предлагаемая модификация никоим образом не даёт возможностей обойти систему типов, это не unsafePerformIO, в конце концов.

A> Поэтому большинство способов их преодоления являются "хаками" тривиально.


Их не надо преодолевать, блин. Всё делается вполне в рамках имеющейся концепции. Авторы просто не понимают метапрограммирования, вообще. Его в принципе очень мало кто понимает.

A> Если собираетесь упорствовать (и, следовательно, мириться с хаками)


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

A> — посмотрите, что делает Matt Morrow — http://moonpatio.com/repos, http://code.haskell.org/~morrow. Кстати, для реализации затеи во всей, так сказать, красе ему приходится использовать (как ниже и предположил lomeo) — plugins, а именно, дубину eval оттуда.


Ну, во первых, это всё же весьма примитивные варианты применения метапрограммирования. Во вторых, то, что я предлагаю, как раз позволяет обойтись без хаков совсем, и сделать это по православному, типобезопасно и кошерно. Понятно, что об этом лучше писать в haskell-prime, но для начала стоит убедиться, что решение того стоит.

A>И еще. Регулярное вещание анонимом обозначает как минимум неуважение к аудитории.


Меня ваше мнение по этому поводу абсолютно не колышет, представьте себе. Если я и зарегистрируюсь, то забуду на следующей же неделе, как назвался. Я прихожу сюда недостаточно часто, чтобы тратить на регистрацию время. Интересные темы тут появляются раз в квартал. Темы, из которых я мог бы вынести решение нужной мне здесь и сейчас практической задачи — и того реже. Эта тема как раз из их числа.
Re[31]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 20.08.09 10:10
Оценка:
Здравствуйте, awson, Вы писали:

A>Здравствуйте, Аноним, Вы писали:


A>И еще. Регулярное вещание анонимом обозначает как минимум неуважение к аудитории. thesz уже намекал на это, однако, даже если Вы и не идентифицируете себя как адресата его намека, я напоминаю, что насчет анонимов в сети существует практически консенсус.


Если вам лично не нравятся комментарии анонимных пользователей — вы можете их игнорироровать, либо попросить администрацию ресурса/форума отключить возможность анонимного постинга в подобные разделы. А ваш "консенсус" отдаёт душком. Зачем вы опускаетесь до попыток унизить собеседника?


Cheers!
Re[28]: Как написать виртуальную машину на LISP
От: thesz Россия http://thesz.livejournal.com
Дата: 20.08.09 12:22
Оценка: -1
Здравствуйте, Аноним, Вы писали:

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


А>>> При том, что мы говорим о вполне конкретном случае применения рефлексии — внутри сплайса, для приложения поименованной функции из другого модуля с известной сигнатурой типа. То есть, о работе с API собственно GHC.

T>>Не, ничего такого.
А> В таком случае следует тему сузить. Меня другие варианты не интересуют.

А для меня твой вариант интересен исключительно в развлекательных целях. Проблемы я буду решать по-другому.

T>>Мы говорим о реализации компилятора Лиспа в виде DSEL на Хаскеле.

А> В виде компилируемого EDSL на Хаскеле с произвольным синтаксисом.

Для этого нужен Template Haskell.

Или кодогенерация, но её ты исключил из рассматриваемых решений.

Про заказчика и defmacro ты ловко ввернул. Уважаю.

Хорошо быть своим собственным заказчиком.

T>>Один из вариантов этой реализации — через Template Haskell.

А> Все другие чрезмерно перанальны.

А по-моему, именно твоё решение наиболее страшное.

T>>Поэтому не надо зацикливаться. И поэтому — а почему бы не попробовать ассоциированные типы и классы типов?

А> Потому, что есть условия:
А>- синтаксис EDSL произволен — ну да ладно, никто не запрещает раскрывать сплайс в код на комбинаторах, это не проблема
А>- он должен компилироваться в Хаскелль
А>- должно быть реализовано метапрограммирование в eDSL. Почему? Так хочет заказчик, и не колышет. В спецификации языка есть defmacro — вынь да положь defmacro в реализации.
А>- общий контекст с хост-языком (решене из п.1. тут тоже подходит)

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

А> Ну и в конце концов — это наиболее общее решение. Любые другие будут являться частным случаем этого подхода.


Я так не думаю. Наоборот, задача содержит столько ограничений, что её решение будет наиболее ограниченным.

T>>Так надо попробовать, нет?

А> Не вижу пути.

Если бы я упёрся в такую проблему, я бы постарался изучить идиоматичный подход к решению.

Поэтому мне интересно, как же ты поступишь.

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

А> Сплайсы потребуются однозначно, поскольку всё это безобразие по условиям игры обязательно должно происходить во время компиляции. В рантайме не должно быть нераскрытых макр.

rewrite rules?..

T>>>>А ты здесь не ошибешься ли?

А>>> Я никогда не исключаю такой возможности. С удовольствием посмотрел бы на пример.
T>>Всё дело в том, что я в Лиспах не разбираюсь.
А> А зря. В этом и разница — я разбираюсь во всём — и в Лиспах, и в Хаскелле, и во всяких там APL-ах и прочих J, и вообще во всём, что только есть.

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

А> И могу выбирать решения из разных миров.


Это я тоже вижу. И вижу упорство, с которым ты натягиваешь решение из Лиспа поверх Хаскеля.

А> А в субкультуре Хаскелля сложились определённые подходы, от которых народ очень не любит отходить.


Я не вижу в этом ничего плохого.

Вот, смотри.

Ты говоришь "нужен defmacro", а на обычный язык это надо перевести "желательна высокая производительность". Или "нужен обобщённый подход". Или как-то ещё.

В мире Хаскеля есть много способов добиться высокой производительности, обобщённого подхода и чего-то ещё.

T>>Почему бы тебе не попробовать выразить свою задачу с типами?

А> Почему ты думаешь, что я не пробовал?

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

Поэтому, я думаю, ты привык видеть везде гвоздь макросов. Поскольку единственный твой инструмент, это молоток метапрограммирования.

T>> К тому же ты анонимен и мы вольны выбирать из сообщений анонимов на РСДН те, что намерены приписать тебе, а также мы вольны отбрасывать те сообщения, что считаем несущественными.

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

То-то я тут наблюдаю пляски вокруг TH вместо переформулировки задачи.

А>>> Из Лиспа Хаскелль таким образом сделать можно, теперь интересно посмотреть и на обратное преобразование.

T>>I'd like to see that feat.
А> В смысле — Хаскелль на Лиспе?

Процесс! Важен процесс!

Процесс создания Хаскеля на Лиспе!

А>>> Задача, конечно же, игрушечная и практического смысла в ней мало, но многие реальные задачи сводятся к чему-то очень похожему.

T>>И решаются ассоциированными типами и типами классов.
А> Не решаются. Важное условие — доступ ко всем определениям во время компиляции.

Подумай ещё раз.

T>>Да зачем?

T>>Я использую Хаскель в течении уже 11 лет, из них четыре года в повседневной работе.
T>>Мне метапрограммирование было нужно только первые две недели этих 11 лет и ещё один раз когда-то недавно. А уж DSL да DSEL я понаписал немало.
А> Не отмазка. Я знаю лисперов, которые лет тридцать на Лиспе пишут, и до сих пор не умеют пользоваться как следует метапрограммированием.

Уверяю тебя, я умею.

Я на ассемблере с макросами (ТурбоАссемблер) написал не менее миллиона строк. И макросов там было много, процентов 5.

А> Я уж не говорю о тех, кто тридцать лет пишет на Фортране, и не умеет пользоваться вообще ничем. Я сам — функциональщик с пятнадцатилетним стажем, но метапрограммированием пользуюсь (кстати, преимущественно в реальных, практических задачах) лишь последние лет шесть.


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

Forth и ассемблер.

А>>> Собственно, всё, связанное с языками — как DSL, так и общего назначения. Rule-based systems, CAD-ы, static code analysis с программируемыми правилами, и т.д.

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

Пока не известно про опровержение в виде Atom (HDL), Atom (язык программирования для встроенных систем) и Bluespec.

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

T>>Значит, надо генерировать типобезопасный ЯП, например, Хаскель.
А> А мне ничем не поможет то, что Хаскелль скажет про конечный результат преобразования. Мне (а точнее, пользователям) нужны чёткие и ясные диагностики на всех этапах.

Пользователю нужно, чтобы всё работало и было сделано в срок.

Количество этапов пользователя не волнует.

T>>Поэтому либо будут $(func ...), либо из не будет. Последнее доступно только с помощью ассоциированных типов и классов типов.

А> Дались тебе эти ассоциированные типы...

Я недавно научился их использовать!

T>> Вот этот параграф твоего комментария навевает на меня грустные мысли: ты хочешь добиться чего-то с искусственными ограничениями.

А> Это не ограничения. Ограничения — это то, что накладывает на меня Хаскелль. И в этом случае — совершенно безосновательно накладывает. А я вообще не люблю ограничения.

Если ты не любишь ограничения, то зачем ты себя сразу ограничил в формулировке задачи?

T>> С одной стороны, ты желаешь получить "прозрачный для пользователя" код, с другой стороны ты не желаешь вкладывать в цитирование (splice) весь модуль (а при этом получается возможность так сделать).

А> Сплайс — часть того же модуля, где и весь остальной код на Хаскелле присутствует. Почему для него должны быть другие правила видимости определений?

Проверил:
B.hs:12:6:
    Declaration splices are not permitted inside declaration brackets


Не работает.

Ну, и ладно.

T>> Получается, что ты просто упёрся в достижении тобой понимаемой цели через метапрограммирование, как его понимаешь ты.

А> У меня есть на это причины — иерархическое метапрограммирование. Другими способами его реализовать нельзя.

http://www.haskell.org/haskellwiki/GHC/Type_families#An_associated_data_type_example

Я думаю, можно.

А>>> Это чрезмерное усложнение. В нашей игрушечной задаче, например, это потребует изменения самого DSL (Лиспа, то есть). Что само по себе уже подозрительно — ведь хотелось бы иметь возможность реализовать любой DSL.

T>>Приведи пример кода, которого ты хочешь добиться.
А>Грубо говоря, в одном модуле определяем
А>$(thlisptop "(defmacro list args (match args ((head . tail) `(cons ,head (list ,@tail))) (() 'nil)))")

А> а в другом уже можем макрой воспользоваться:

А>$(thlisp "(map (lambda (x) (* x x)) (list 1 2 3 4))")

И что в результате должно получиться?

вот мой вариант в ожидании твоего ответа:
{-# LANGUAGE GADTs, TypeFamilies, EmptyDataDecls, FlexibleInstances #-}

module L where

data Macro_list where
    Macro_list :: Macro_list

data HasMacro
data Expanded

type family AnyMacro a b
type instance AnyMacro HasMacro b = HasMacro
type instance AnyMacro a HasMacro = HasMacro
type instance AnyMacro Expanded Expanded = Expanded

data Lisp hasMacro where
    LAtom :: String -> Lisp hasMacro
    LCon :: Lisp hd -> Lisp tl -> Lisp (AnyMacro hd tl)
    LApp :: LispMacro t => t -> Lisp hd -> Lisp HasMacro

class LispMacro a where
    -- apply a macro.
    apply :: a -> Lisp Expanded -> Lisp Expanded

instance LispMacro (Lisp Expanded) where
    apply hd tl = LCon hd tl

instance LispMacro Macro_list where
    apply Macro_list args = args

expand :: Lisp a -> Lisp Expanded
expand (LAtom a) = LAtom a
expand (LCon a b) = LCon (expand a) (expand b)
expand (LApp t args) = apply t (expand args)


Можно делать reify для каждого символа, что не в области видимости. Но не для самого символа, а для имени ("Macro_"++имя). defmacro name должно создать тип ("Macro_"++name) и реализацию класса LispMacro для него (которая правильным образом отработает раскрытие).

Идея, я думаю, ясна.

А>>>>> Если это EDSL? Препроцессоры городить — это позорная сиплюсплюсщина. Метапрограммирование на то и нужно, чтоб без препроцессоров обходиться.

T>>>>Комбинаторы?
А>>> А если синтаксис Хаскелля не нужен, а нужен совсем другой?
T>>Внешний синтаксис через комбинаторы?
А> Да какой он к бесам внешний. Не, я понимаю, можно извратиться, поднапрячься, и даже что-то похожее на бейсик изобразить — но это именно что извращение. Несистемное решение. Я же ещё не сказал, что к этим eDSL нужна полноценная поддержка от IDE, со всякими там intellisense и прочей ерундой.

Кстати, а ты бейсик, встроенный в Хаскель, видел?

А>>> А если производительности такой интерпретации не хватает?

T>>par/pseq для распараллеливания?
А> Не смешно даже.

И почему конкретно?

А>>> А если кроме родной Хаскелевой системы типов хочется ещё своих сложных проверок добавить?

T>>Внешний DSL?
А> Не вижу существенных отличий в методах реализации внешних DSL от встраиваемых.

А они есть!

Прям, как в анекдоте.

T>>А что за проверки, приведи пример.

А> Например — наличие таблицы с таким-то именем в базе данных. Наличие прав у текущего пользоватея на выполнение такой-то операции. И т.п. Всё — в статике, во время компиляции.

Кодогенерация.

T>>>>Как много комбинаторных библиотек ты написал?

А>>> До хрена. Например, тот же packrat я делал и на комбинаторах, и метапрограммированием. Второй вариант быстрее ну очень заметно, и при этом позволяет пользоваться приличным синтаксисом.
T>>Задам вопрос по-другому: писал ли ты комбинаторную библиотеку на Хаскеле с использованием {-# INLINE #-} и {-# RULES #-}?
А> Не вижу, чем оно помогло бы в реализации того же Packrat. Я использовал {-# SPECIALIZE ... #- }

Ну, ByteString оно ускорило.

T>>>>С развитием маленькие группы людей не справляются. Даже с развитием естественных языков, что говорить о менее повседневных вещах.

А>>> Вот и ворую идеи у сообществ лиспа, немерла, Хаскелля, Axiom и десятков других. Ничего не отдавая им за это.
T>>Это ты так думаешь.
А> Думаю, что ворую? Да нет, знаю, что ворую — вон, работает всё в конкретных проектах, каши не просит. Мне хорошо, а немерлисты о факте воровства даже и не в курсе.

Да, рефлексия у тебя на нуле.

T>>>>К тому же метапрограммирование само по себе не имеет ценности. Оно имеет ценность в качестве одного из инструментов.

А>>> Именно. Но надо знать, как инструментом пользоваться. И это знание имеет ценность.
T>>Это даже не очень и смешно. Зачем кому-то знание о том, как пользоваться не очень ценным (из-за отсутствия развития) инструментом?
А> Хе хе. Вот пока большинство думает, что инструментарий "не очень ценный", у тех немногих, кто знает его ценность, имеется гигантское конкурентное преимущество.

Почему Лисп не используется в описании аппаратуры?

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

А>>> Я не настолько альтруистичен. Но так уж и быть, в этом случае нарушу свои правила.
T>>Уверяю тебя, я всё и всегда делаю ради собственной выгоды.
А> В чём персональная выгода от пропаганды Хаскелля? Кому надо — и так все давно в курсе.

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

А> Моя выгода от этой дискуссии очевидна — я могу или найти решение в рамках заданных условий, или убедиться, что его нет. Экономия времени, однако.


Да как-то ты не очень и ищешь. И условия выбрал специально тяжёлые.

T>>>>Для этого уже тип не нужен (не может быть двух определений с разными типами в одном модуле). Список используемых модулей нужен, но и всё.

А>>> Тип нужен, чтобы это определение применить.
T>>Тогда — ассоциированные типы.
А> Как это мне поможет динамически вытащить определение по его имени?

Иными словами, ты про подходы Хаскеля к твоей проблеме не знаешь.

Так и запишем, что вот в этой ветке обсуждения аноним противоречит сам себе. Причём, даже внутри одного комментария.

T>>>>А его, этот список модулей, можно получить, поднявшись на уровень выше, как я вверху предложил. Надо пройти по всем Name и взять у них модули.

А>>> Увы, увы, это ещё не решение. Попробую пропатчить ghc и показать то минимальное изменение, которого достаточно для этой фичи.
T>>Посмотрел на твоё решение повнимательней. Я не думаю, что тебе надо вызывать какую-либо функцию.
А> Ты не понимаешь Лиспа, совершенно. И по этому примеру тем более не сможешь понять, где там надо впихнуть макры.

Уверяю тебя, я очень умный.

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

T>>--например:

T>>[$thlisp|(begin .... print ....)|]
T>>[/haskell]
А> В данном случае толку от них никакого — что кавычки, что палочки, один хрен. Был бы у Хаскелля парсер на PEG — другое дело, можно было бы органично встраивать в него любой синтаксис.

Кстати, а на Лискель ты смотрел?

T>>>>Потому, что API TH под это не заточено. Оно заточено под другие дела.

А>>> Какие же?
T>>Например, foreign генерировать. Всякого рода instance создавать.
А> Примитивщина.

А полезно. Даже для твоих целей.

T>>Что еще...

T>>Текст слегка видоизменять, я думаю. Делать небольшие{/i] языки.
А> А небольшие языки проще всего делать итерационным надстраиванием над языками побольше. Мне нужно иерархическое метапрограммирование, а не просто "foreign генерить".

Да не нужно оно тебе. Не. Нужно.

Это ты собственную важность демонстрируешь, своими рекламациями насчёт "проще всего делать итерационным надстраиванием" и "нужно иерархическое метапрограммирование".

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

Но при этом ты не приводишь данных, почему он самый лучший и эффективный, только анекдоты.

Я, например, подозреваю, что ты не работаешь в команде. Твой код никто не правит. Я подозреваю, более того, что количество ошибок в твоём коде достаточно высоко, а исправление трудоёмко.

Проведи эксперимент, сравни [i]чужую
производительность на разных подходах, оцени количество кода, количество ошибок после проверки кода и после commit в общий репозиторий и только после устойчивого положительного результата настаивай на своём подходе.

T>>>>Помниться, мне макросов хотелось недели две, пока до функций высшего порядка не дошёл.

А>>> Мне никакие функции высшего порядка макросы не заменят. Слишком много интересных применений для макросов я нашел.
T>>Это всё от преждевременной оптимизации.
А> Нет, оптимизация в данном случае совершенно не при чём. Важна семантика.

Тогда генерируй Лисп и раскрывай по необходимости. Лениво, так сказать.

А>>> Они явно от этой проблемы просто отмахнулись.

T>>А почему?
А> По причине непонимания последствий.

Да ты что!

Все не в ногу, а ты в ногу!

Все идиоты, а ты умный.

Или не все идиоты?

Если не все идиоты, то почему они могут игнорировать столь ценимое тобой решение? А почему его игнорируют те, кто про него знают? Не задавался такими вопросами?

А>>> Я когда-то уже обсуждал с SPJ статическое метапрограммирование — так тогда он вообще не понимал, для чего оно может быть нужно в Хаскелле, и не знал, что с ним делают в Лиспе. Потом мнение поменял, но до просветления явно ещё пару шагов требуется. Инерция мышления, однако.

T>>Так то, что с ним делают в Лиспе — получают скорость выполнения, — делают в Хаскеле с помощью оптимизаций.
А> Нет, то, что с ним делают в Лиспе, в Хаскелле не делают вообще.

Нет, то, что ты знаешь о Хаскеле, не даёт тебе права утверждать вообще ничего.

Потому, что в Хаскеле делают по-Хаскельному то, что в Липе делают по-Лисповски.

А про Хаскельный подход ты знаешь чуть более, чем ничего.

T>>Которые оптимизации — как в примере с теми же самыми генериками выше по теме в дискуссии с lomeo, — могут быть применимы где-то ещё, не только в каком-то определённом месте.

А> Кстати да, ast:visit таки очень неплохой пример преимуществ метапрограммирования.

Чем он хуже generic с оптимизациями?
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[29]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 20.08.09 13:13
Оценка: +1
Здравствуйте, thesz, Вы писали:

А>> В таком случае следует тему сузить. Меня другие варианты не интересуют.


T>А для меня твой вариант интересен исключительно в развлекательных целях. Проблемы я буду решать по-другому.


Это существенно ограничивает круг проблем, которые ты способен решать (за приемлемое время).

T>>>Один из вариантов этой реализации — через Template Haskell.

А>> Все другие чрезмерно перанальны.

T>А по-моему, именно твоё решение наиболее страшное.


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

T>Я бы остановился на комбинаторах. Всё равно они не сложнее, чем обычные запятые да бинарные операторы.


Во первых — опять, производительность. Во вторых, это не решает поставленной задачи.

T>Я так не думаю. Наоборот, задача содержит столько ограничений, что её решение будет наиболее ограниченным.


Я уже понял, что ты абсолютно не понимаешь, что такое метапрограммирование.

T>Если бы я упёрся в такую проблему, я бы постарался изучить идиоматичный подход к решению.


Идиоматический подход мне известен и интереса не представляет. Я его (комбинаторы, rewrite rules, SPECIALIZE, и т.п.) использую там, где в этом есть смысл.

А>> Сплайсы потребуются однозначно, поскольку всё это безобразие по условиям игры обязательно должно происходить во время компиляции. В рантайме не должно быть нераскрытых макр.


T>rewrite rules?..


Не, ты определённо не пытаешься понять, о чём собственно идёт речь.

Нельзя определение rewrite rule сгенерить в template haskell. Кроме того, уж это точно запредельно перанальное решение было бы. На кой хрен мне эти rewrite rules, когда надо определить свой (и предельно тривиальный, следует заметить) macro expander. Который должен срабатывать, кроме всего прочего, на этапе задолго до генерации кода на Haskell.

А>> А зря. В этом и разница — я разбираюсь во всём — и в Лиспах, и в Хаскелле, и во всяких там APL-ах и прочих J, и вообще во всём, что только есть.


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


Да нет, никакого представления ты получить не мог в принципе. ы, Во первых, ты понятия не имеешь ни о Лиспе, ни о метапрограммировании, во вторых — я не дал достаточной информации. У тебя есть какие-то свои забавные представления о том, "как правильно". Всё, что в них не вписывается, всё, что использует незнакомые тебе теории и модели, ты воспринимаешь заведомо как ошибку.

А>> И могу выбирать решения из разных миров.


T>Это я тоже вижу. И вижу упорство, с которым ты натягиваешь решение из Лиспа поверх Хаскеля.


В данном случае я просто не вижу, почему это решение должно противоречить идеологии Хаскелля. И одно только это решение расширяет возможности языка совершенно неограниченным образом. Всякие там примитивные детские rewrite rules рядом с одной этой возможностью — полная фигня (и они поверх этой фичи реализуются тривиально, кстати).

А>> А в субкультуре Хаскелля сложились определённые подходы, от которых народ очень не любит отходить.


T>Я не вижу в этом ничего плохого.


А я считаю это путём в болото.

T>Вот, смотри.


T>Ты говоришь "нужен defmacro",


Я говорю — "в спецификации DSL есть такая фича". Или она реализуема, и тогда наш хост-язык достаточно мощный и общий, или она нереализуема. Я не намерен обсуждать причины включения такой фичи в DSL. В данном случае показательно уже хотя бы то, что реализовать её разумным и понятным способом нельзя. Исключительно по причине упёртости разработчиков TH, не удосужившихся разобраться в сути метапрограммирования.

T> а на обычный язык это надо перевести "желательна высокая производительность". Или "нужен обобщённый подход". Или как-то ещё.


Это уже не важно, в такой постановке.

T>В мире Хаскеля есть много способов добиться высокой производительности, обобщённого подхода и чего-то ещё.


И ни к одному из этих способов TH доступа не даёт. Что следует читать как "TH неполноценен".

T>>>Почему бы тебе не попробовать выразить свою задачу с типами?

А>> Почему ты думаешь, что я не пробовал?

T> Потому, что ты не привёл результатов.


На фига тебе эти результаты? Я решаю совсем другую задачу, игрушечный Lisp — это сведённый до понятного уровня тривиальный пример.

T> Ты сразу схватился за привычный тебе инструмент: метапрограммирование. Причём схватился за него в наиболее привычной тебе манере: кодогенерации.


Альтернативные инструменты этой поставленной задачи не решают.

T>Поэтому, я думаю, ты привык видеть везде гвоздь макросов. Поскольку единственный твой инструмент, это молоток метапрограммирования.


Да, это так. Я то знаю всю мощь этого молотка.

T>То-то я тут наблюдаю пляски вокруг TH вместо переформулировки задачи.


Я уже объяснил, почему я не намерен переформулировать задачу. Не понимаешь до сих пор?

А>>>> Из Лиспа Хаскелль таким образом сделать можно, теперь интересно посмотреть и на обратное преобразование.

T>>>I'd like to see that feat.
А>> В смысле — Хаскелль на Лиспе?

T>Процесс! Важен процесс!


T>Процесс создания Хаскеля на Лиспе!


Не понял пассажа.

Хаскелль на Лиспе (встраиваемый, разделяющий с ним контекст, и т.п.) я сделать могу. Эффективно. И весьма просто. Лисп на Хаскелле с такими же свойствами сделать нельзя. Вот и вся разница.

А>>>> Задача, конечно же, игрушечная и практического смысла в ней мало, но многие реальные задачи сводятся к чему-то очень похожему.

T>>>И решаются ассоциированными типами и типами классов.
А>> Не решаются. Важное условие — доступ ко всем определениям во время компиляции.

T>Подумай ещё раз.


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

А>> Не отмазка. Я знаю лисперов, которые лет тридцать на Лиспе пишут, и до сих пор не умеют пользоваться как следует метапрограммированием.


T>Уверяю тебя, я умею.


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

T>Я на ассемблере с макросами (ТурбоАссемблер) написал не менее миллиона строк. И макросов там было много, процентов 5.


Да какое это на фиг метапрограммирование? Это фигня, банальные макры.

А>> Я уж не говорю о тех, кто тридцать лет пишет на Фортране, и не умеет пользоваться вообще ничем. Я сам — функциональщик с пятнадцатилетним стажем, но метапрограммированием пользуюсь (кстати, преимущественно в реальных, практических задачах) лишь последние лет шесть.


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


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

T>Forth и ассемблер.


Да уж... Даже не смешно.

T>>>Значит, надо генерировать типобезопасный ЯП, например, Хаскель.

А>> А мне ничем не поможет то, что Хаскелль скажет про конечный результат преобразования. Мне (а точнее, пользователям) нужны чёткие и ясные диагностики на всех этапах.

T>Пользователю нужно, чтобы всё работало и было сделано в срок.


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

T>Количество этапов пользователя не волнует.


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

T>>>Поэтому либо будут $(func ...), либо из не будет. Последнее доступно только с помощью ассоциированных типов и классов типов.

А>> Дались тебе эти ассоциированные типы...

T>Я недавно научился их использовать!


Я так и подумал.

T>>> Вот этот параграф твоего комментария навевает на меня грустные мысли: ты хочешь добиться чего-то с искусственными ограничениями.

А>> Это не ограничения. Ограничения — это то, что накладывает на меня Хаскелль. И в этом случае — совершенно безосновательно накладывает. А я вообще не люблю ограничения.

T>Если ты не любишь ограничения, то зачем ты себя сразу ограничил в формулировке задачи?


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

T>>> С одной стороны, ты желаешь получить "прозрачный для пользователя" код, с другой стороны ты не желаешь вкладывать в цитирование (splice) весь модуль (а при этом получается возможность так сделать).

А>> Сплайс — часть того же модуля, где и весь остальной код на Хаскелле присутствует. Почему для него должны быть другие правила видимости определений?

T>Проверил:



Ты не понял.

 let a = 2
     $( [| a + a |] )


Для созданного сплайсом кода видимость вполне определена. Какого хрена в неё надо вмешиваться?

T>Я думаю, можно.


Не понимаю.

T>И что в результате должно получиться?


В результате должно получиться ровно то же, что при раскрытии $(thlisp "(map (lambda (x) (* x x)) (cons 1 (cons 2 (cons 3 (cons 4 nil)))))")

T>вот мой вариант в ожидании твоего ответа:


Ок, сейчас посмотрю — на первый взгляд мне не кажется, что это в принципе может вообще работать — reify мне instance не даст.

T>Можно делать reify для каждого символа, что не в области видимости. Но не для самого символа, а для имени ("Macro_"++имя). defmacro name должно создать тип ("Macro_"++name) и реализацию класса LispMacro для него (которая правильным образом отработает раскрытие).


Ты, похоже, не понял, в какой момент отрабатывает expand...

T>Идея, я думаю, ясна.


Всё ещё не ясна.

T>Кстати, а ты бейсик, встроенный в Хаскель, видел?


Конечно же видел. И аналогичной техникой я часто пользуюсь. В данном же случае это не вариант.

T>И почему конкретно?


Потому, что не всё можно параллелить.

А>> Не вижу существенных отличий в методах реализации внешних DSL от встраиваемых.


T>А они есть!


Не-а. Их нет. Внешние DSL проще всего реализуются как частный случай встраиваемых.

А>> Например — наличие таблицы с таким-то именем в базе данных. Наличие прав у текущего пользоватея на выполнение такой-то операции. И т.п. Всё — в статике, во время компиляции.


T>Кодогенерация.


Которая является частным случаем метапрограммирования.

T>>>Задам вопрос по-другому: писал ли ты комбинаторную библиотеку на Хаскеле с использованием {-# INLINE #-} и {-# RULES #-}?

А>> Не вижу, чем оно помогло бы в реализации того же Packrat. Я использовал {-# SPECIALIZE ... #- }

T>Ну, ByteString оно ускорило.


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

А>> Моя выгода от этой дискуссии очевидна — я могу или найти решение в рамках заданных условий, или убедиться, что его нет. Экономия времени, однако.


T>Да как-то ты не очень и ищешь. И условия выбрал специально тяжёлые.


Я решаю конкретную задачу — грубо говоря, eval внутри splice. Условия задачи составлены таким образом, чтоб неприменно сводиться к основному требованию. Для чего мне это надо — не существенные детали. Уж поверь — как сделать идиоматически то же самое я прекрасно представляю, и мне не интересно выслушивать предложения пойти этим путём.

А>> Ты не понимаешь Лиспа, совершенно. И по этому примеру тем более не сможешь понять, где там надо впихнуть макры.


T>Уверяю тебя, я очень умный.


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

T>А Лисп не настолько сложный, чтобы его не понять. Как и метапрограммирование.


Именно. Всё очень просто. Но ты не понимаешь — поскольку мыслишь в совершенно иных категориях.

А>> В данном случае толку от них никакого — что кавычки, что палочки, один хрен. Был бы у Хаскелля парсер на PEG — другое дело, можно было бы органично встраивать в него любой синтаксис.


T>Кстати, а на Лискель ты смотрел?


Смотрел, конечно же. У меня несколько другая задача — не Хаскелль с синтаксисом Лиспа, а встроенный в Хаскелль полноценный Лисп (то есть, eager, dynamic, и всё такое прочее).

А>> А небольшие языки проще всего делать итерационным надстраиванием над языками побольше. Мне нужно иерархическое метапрограммирование, а не просто "foreign генерить".


T>Да не нужно оно тебе. Не. Нужно.


Нужно-нужно.

T>Это ты собственную важность демонстрируешь, своими рекламациями насчёт "проще всего делать итерационным надстраиванием" и "нужно иерархическое метапрограммирование".


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

T>Ты не можешь от этого отказаться потому, что считаешь твой подход самым лучшим и эффективным. Соответственно, твоё мнение самое важное.


Для моих задач мой подход работает лучше всех прочих. Меня не интересуют другие задачи.

T>Но при этом ты не приводишь данных, почему он самый лучший и эффективный, только анекдоты.


Я же уже сказал — спорить и убеждать я не намерен.

T>Я, например, подозреваю, что ты не работаешь в команде. Твой код никто не правит.


Неверное подозрение.

T> Я подозреваю, более того, что количество ошибок в твоём коде достаточно высоко, а исправление трудоёмко.


Абсолютно неверный вывод.

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

T>Проведи эксперимент, сравни чужую производительность на разных подходах, оцени количество кода, количество ошибок после проверки кода и после commit в общий репозиторий и только после устойчивого положительного результата настаивай на своём подходе.


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

А>> Нет, оптимизация в данном случае совершенно не при чём. Важна семантика.


T>Тогда генерируй Лисп и раскрывай по необходимости. Лениво, так сказать.


Второе условие — код надо скрыть.

T>Если не все идиоты, то почему они могут игнорировать столь ценимое тобой решение? А почему его игнорируют те, кто про него знают? Не задавался такими вопросами?


Те, кто про него знают, Хаскеллем не пользуются.

T>А про Хаскельный подход ты знаешь чуть более, чем ничего.


Ну ну. Посмешил.

А>> Кстати да, ast:visit таки очень неплохой пример преимуществ метапрограммирования.


T>Чем он хуже generic с оптимизациями?


Компактнее. Услойчивее к изменениям структуры. Лучше подходит для тривиальных преобразований.
Re[30]: Как написать виртуальную машину на LISP
От: FR  
Дата: 20.08.09 13:38
Оценка:
Здравствуйте, Аноним, Вы писали:

А> Ну, твоего кода я вообще не видел, но представление имею, как он может выглядеть. Человек, принципиально не понимающий Лиспа в частности и метапрограммирования вообще, может та-акого понаписать...


Человек плотно писавший на форте не может не понимать метапрограммирования.
Re[31]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 20.08.09 13:51
Оценка:
Здравствуйте, FR, Вы писали:

FR>Человек плотно писавший на форте не может не понимать метапрограммирования.


В форте не доступно серьёзное метапрограммирование. Так, макропрограммирование только.
Re[32]: Как написать виртуальную машину на LISP
От: FR  
Дата: 20.08.09 13:52
Оценка:
Здравствуйте, Аноним, Вы писали:

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


FR>>Человек плотно писавший на форте не может не понимать метапрограммирования.


А> В форте не доступно серьёзное метапрограммирование. Так, макропрограммирование только.


И чем определяется серъезность?
Re[30]: Как написать виртуальную машину на LISP
От: thesz Россия http://thesz.livejournal.com
Дата: 20.08.09 16:02
Оценка:
Здравствуйте, Аноним, Вы писали:

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


T>>А для меня твой вариант интересен исключительно в развлекательных целях. Проблемы я буду решать по-другому.

А> Это существенно ограничивает круг проблем, которые ты способен решать (за приемлемое время).

Да ты чо!

Давай возьмём любое приложение и посмотрим, как много там можно приложить метапрограммирования.

T>>>>Один из вариантов этой реализации — через Template Haskell.

А>>> Все другие чрезмерно перанальны.
T>>А по-моему, именно твоё решение наиболее страшное.
А> Ну, твоего кода я вообще не видел, но представление имею, как он может выглядеть. Человек, принципиально не понимающий Лиспа в частности и метапрограммирования вообще, может та-акого понаписать...

Наверное, что-то простое и наиболее подходящее к проблеме? Уж точно без метапрограммирования там, где оно не нужно. И с метапрограммированием там, где нужно.

T>>Я бы остановился на комбинаторах. Всё равно они не сложнее, чем обычные запятые да бинарные операторы.

А> Во первых — опять, производительность. Во вторых, это не решает поставленной задачи.

Производительность — см. другие способы ускорения программ.

А то, что не решает поставленной задачи, так это задача так поставлена, что её хрен решить.

T>>Я так не думаю. Наоборот, задача содержит столько ограничений, что её решение будет наиболее ограниченным.

А> Я уже понял, что ты абсолютно не понимаешь, что такое метапрограммирование.

В свете количества твоих ошибок это выглядит, скорее, как комплимент.

А>>> А зря. В этом и разница — я разбираюсь во всём — и в Лиспах, и в Хаскелле, и во всяких там APL-ах и прочих J, и вообще во всём, что только есть.

T>>Про степень твоего знания Хаскеля и типичных для него решений я получил более, чем достаточную информацию.
А> Да нет, никакого представления ты получить не мог в принципе. ы, Во первых, ты понятия не имеешь ни о Лиспе, ни о метапрограммировании, во вторых — я не дал достаточной информации.

Ты не переживай.

Ну, не знаю я Лисп,

А> У тебя есть какие-то свои забавные представления о том, "как правильно". Всё, что в них не вписывается, всё, что использует незнакомые тебе теории и модели, ты воспринимаешь заведомо как ошибку.


А>>> И могу выбирать решения из разных миров.


T>>Это я тоже вижу. И вижу упорство, с которым ты натягиваешь решение из Лиспа поверх Хаскеля.


А> В данном случае я просто не вижу, почему это решение должно противоречить идеологии Хаскелля. И одно только это решение расширяет возможности языка совершенно неограниченным образом. Всякие там примитивные детские rewrite rules рядом с одной этой возможностью — полная фигня (и они поверх этой фичи реализуются тривиально, кстати).


А>>> А в субкультуре Хаскелля сложились определённые подходы, от которых народ очень не любит отходить.


T>>Я не вижу в этом ничего плохого.


А> А я считаю это путём в болото.


T>>Вот, смотри.


T>>Ты говоришь "нужен defmacro",


А> Я говорю — "в спецификации DSL есть такая фича". Или она реализуема, и тогда наш хост-язык достаточно мощный и общий, или она нереализуема. Я не намерен обсуждать причины включения такой фичи в DSL. В данном случае показательно уже хотя бы то, что реализовать её разумным и понятным способом нельзя. Исключительно по причине упёртости разработчиков TH, не удосужившихся разобраться в сути метапрограммирования.


T>> а на обычный язык это надо перевести "желательна высокая производительность". Или "нужен обобщённый подход". Или как-то ещё.


А> Это уже не важно, в такой постановке.


T>>В мире Хаскеля есть много способов добиться высокой производительности, обобщённого подхода и чего-то ещё.


А> И ни к одному из этих способов TH доступа не даёт. Что следует читать как "TH неполноценен".


T>>>>Почему бы тебе не попробовать выразить свою задачу с типами?

А>>> Почему ты думаешь, что я не пробовал?

T>> Потому, что ты не привёл результатов.


А> На фига тебе эти результаты? Я решаю совсем другую задачу, игрушечный Lisp — это сведённый до понятного уровня тривиальный пример.


T>> Ты сразу схватился за привычный тебе инструмент: метапрограммирование. Причём схватился за него в наиболее привычной тебе манере: кодогенерации.


А> Альтернативные инструменты этой поставленной задачи не решают.


T>>Поэтому, я думаю, ты привык видеть везде гвоздь макросов. Поскольку единственный твой инструмент, это молоток метапрограммирования.


А> Да, это так. Я то знаю всю мощь этого молотка.


T>>То-то я тут наблюдаю пляски вокруг TH вместо переформулировки задачи.


А> Я уже объяснил, почему я не намерен переформулировать задачу. Не понимаешь до сих пор?


А>>>>> Из Лиспа Хаскелль таким образом сделать можно, теперь интересно посмотреть и на обратное преобразование.

T>>>>I'd like to see that feat.
А>>> В смысле — Хаскелль на Лиспе?

T>>Процесс! Важен процесс!


T>>Процесс создания Хаскеля на Лиспе!


А> Не понял пассажа.


А> Хаскелль на Лиспе (встраиваемый, разделяющий с ним контекст, и т.п.) я сделать могу. Эффективно. И весьма просто. Лисп на Хаскелле с такими же свойствами сделать нельзя. Вот и вся разница.


А>>>>> Задача, конечно же, игрушечная и практического смысла в ней мало, но многие реальные задачи сводятся к чему-то очень похожему.

T>>>>И решаются ассоциированными типами и типами классов.
А>>> Не решаются. Важное условие — доступ ко всем определениям во время компиляции.

T>>Подумай ещё раз.


А> Не строй из себя гуру — тебе это не идёт. Вместо попыток сделать вид, что знаешь тайное решение и понимаешь, что надо делать — привёл бы свой вариант. Я бы показал, почему это решением не является.


А>>> Не отмазка. Я знаю лисперов, которые лет тридцать на Лиспе пишут, и до сих пор не умеют пользоваться как следует метапрограммированием.


T>>Уверяю тебя, я умею.


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


T>>Я на ассемблере с макросами (ТурбоАссемблер) написал не менее миллиона строк. И макросов там было много, процентов 5.

А> Да какое это на фиг метапрограммирование? Это фигня, банальные макры.

CREATE..DOES> банальные макры?

Великолепно.

Надо тебя ещё на что-нибудь раскрутить.

А>>> Я уж не говорю о тех, кто тридцать лет пишет на Фортране, и не умеет пользоваться вообще ничем. Я сам — функциональщик с пятнадцатилетним стажем, но метапрограммированием пользуюсь (кстати, преимущественно в реальных, практических задачах) лишь последние лет шесть.

T>>А я им активно пользовался первые шесть лет моего более, чем двадцатилетнего стажа.
А> То, чем ты пользовался, это никакое не метапрограммирование. Тебя обманули.

http://forth.rhub.firstvds.ru/books.php
К.ТАУНСЕНД, Д.ФОХТ. ПРОЕКТИРОВАНИЕ И ПРОГРАММНАЯ РЕАЛИЗАЦИЯ ЭКСПЕРТНЫХ СИСТЕМ НА ПЕРСОНАЛЬНЫХ ЭВМ. Перевод с английскогоВ.А.Кондратенко, С. В. Трубицына. Предисловие Г.С.Осипова.

Там рассказано, как парой килобайт кода на Форте сделать Лисп, да со скобочками, а не просто так, а на Лиспе потом написать Пролог, на котором формулировать правила экспертных систем.

T>>Forth и ассемблер.

А> Да уж... Даже не смешно.

Как я понимаю, ты и про Форт не очень много знаешь.

T>>>> Вот этот параграф твоего комментария навевает на меня грустные мысли: ты хочешь добиться чего-то с искусственными ограничениями.

А>>> Это не ограничения. Ограничения — это то, что накладывает на меня Хаскелль. И в этом случае — совершенно безосновательно накладывает. А я вообще не люблю ограничения.
T>>Если ты не любишь ограничения, то зачем ты себя сразу ограничил в формулировке задачи?
А> Потому что этот подход снимает вообще любые ограничения, сразу. Это способ избавиться от ограничений навсегда.

Про фальсифицируемость и Карла Поппера ты не слышал, нет?

T>>И что в результате должно получиться?

А> В результате должно получиться ровно то же, что при раскрытии $(thlisp "(map (lambda (x) (* x x)) (cons 1 (cons 2 (cons 3 (cons 4 nil)))))")
T>>вот мой вариант в ожидании твоего ответа:
А> Ок, сейчас посмотрю — на первый взгляд мне не кажется, что это в принципе может вообще работать — reify мне instance не даст.

Вызов instance тебе даст упрощение, которое будет проводиться при вызове того, чему присвоили $(thlisp ...). Вместо вызова макроопределения (macroname macroArgs) (на Хаскеле LCon macroName macroArgs) per se ты должен сделать THLisp.expand (LApp Macro_macroname macroArgs). Macro_macroname раскроет своё тело с подстановкой macroArgs в момент обращения к значению.

T>>Можно делать reify для каждого символа, что не в области видимости. Но не для самого символа, а для имени ("Macro_"++имя). defmacro name должно создать тип ("Macro_"++name) и реализацию класса LispMacro для него (которая правильным образом отработает раскрытие).

А> Ты, похоже, не понял, в какой момент отрабатывает expand...

В момент обращения.

T>>Идея, я думаю, ясна.

А> Всё ещё не ясна.

Здесь я умываю руки.

Я и так рассказал много больше, чем услышал. Хотя надеялся на обратное, тем более, что начальное заявление было твоим
Автор:
Дата: 12.08.09
(надеюсь, что твоим, а то вас анонимов не поймёшь).

T>>Кстати, а ты бейсик, встроенный в Хаскель, видел?

А> Конечно же видел. И аналогичной техникой я часто пользуюсь. В данном же случае это не вариант.

А про такой вариант
Автор: geniepro
Дата: 13.02.09
?

Может, что интересное для себя извлечёшь.

T>>И почему конкретно?

А> Потому, что не всё можно параллелить.

То, что работает долго, обычно можно.

А>>> Не вижу существенных отличий в методах реализации внешних DSL от встраиваемых.

T>>А они есть!
А> Не-а. Их нет. Внешние DSL проще всего реализуются как частный случай встраиваемых.

Ты свои комментарии не читаешь, эт точно.

Так проколоться в трех предложениях суммарным объёмов 12 слов...

А>>> Например — наличие таблицы с таким-то именем в базе данных. Наличие прав у текущего пользоватея на выполнение такой-то операции. И т.п. Всё — в статике, во время компиляции.

T>>Кодогенерация.
А> Которая является частным случаем метапрограммирования.

Или наоборот.

А>>> Ты не понимаешь Лиспа, совершенно. И по этому примеру тем более не сможешь понять, где там надо впихнуть макры.

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

Ты, видимо, не знаешь, что верткие хоккеисты, разящие боксёры, быстрые спринтеры и даже молниеносный Брюс Ли — все они развивали и развивают мышечную силу.

Брюс Ли, к примеру, приседал со штангой, подбирая вес так, чтобы выполнить 2 подхода по 12 повторений.

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

О практическом уме говорит способность выдать правильное и применимое решение. Очень показательно отсутствие этих двух пунктах в твоём параграфе выше.

T>>А Лисп не настолько сложный, чтобы его не понять. Как и метапрограммирование.

А> Именно. Всё очень просто. Но ты не понимаешь — поскольку мыслишь в совершенно иных категориях.

Я понимаю.

Но я понимаю, также, что не все задачи требуют своего ЯП с настолько своим синтаксисом, что надо столь сильно изощряться.

На моей памяти таких задач раз, два и обчёлся.

T>>Ты не можешь от этого отказаться потому, что считаешь твой подход самым лучшим и эффективным. Соответственно, твоё мнение самое важное.

А> Для моих задач мой подход работает лучше всех прочих. Меня не интересуют другие задачи.

Ну, как бы это сказать-то...

Мне бы хотелось, по результатам этой дискуссии, твоего признания, что ты не всё понимаешь в Хаскеле, Форте и других языках.

Из этого будет следовать вывод, что твой текущий подход не самый лучший, но я его опущу.

T>> Я подозреваю, более того, что количество ошибок в твоём коде достаточно высоко, а исправление трудоёмко.

А> Абсолютно неверный вывод.

Это не только мой вывод, это вывод бывших лисперов.

А> Как раз мой код править гораздо проще, чем то, что делаешь ты. Поскольку любое преобразование между языками у меня всегда тривиальное (сложные преобразования просто запрещены), и любой язык строго определён, то ошибиться там просто негде, да и компилятор не позволит.


Ты, вон, приведи код функции, что не даёт подать на свой вход код с нераскрытыми макросами.

T>>Проведи эксперимент, сравни чужую производительность на разных подходах, оцени количество кода, количество ошибок после проверки кода и после commit в общий репозиторий и только после устойчивого положительного результата настаивай на своём подходе.

А> У меня достаточно данных — мой подход позволяет новому человеку быстро въехать в процесс, и защищён от глупых ошибок. Главное — он тупой. Очень тупой, тупее придумать нельзя. Твой же подход — заумный и требует напряга мозгов. Лично я мозгами пользоваться вообще не люблю.

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

Чем для структурирования программ пользуешься ты?

А>>> Нет, оптимизация в данном случае совершенно не при чём. Важна семантика.

T>>Тогда генерируй Лисп и раскрывай по необходимости. Лениво, так сказать.
А> Второе условие — код надо скрыть.

У тебя условия появляются по ходу дискуссии.

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

"А вот тебе ещё условие. А вот посмотрим, как ты с ним справишься. Ага, не справился! Вот и я не могу. Да ты, оказывается, не умней меня."

Давай так.

Идиоматический подход в Хаскеле таков: сперва надо получить хоть какую-то реализацию просто на Хаскеле, затем постепенно надо переносить её в TH или комбинаторы, вплоть до получения необходимой формы.

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

T>>Если не все идиоты, то почему они могут игнорировать столь ценимое тобой решение? А почему его игнорируют те, кто про него знают? Не задавался такими вопросами?

А> Те, кто про него знают, Хаскеллем не пользуются.

То есть, ты Хаскелем не пользуешься?

Ты не читаешь свои комментарии.

T>>А про Хаскельный подход ты знаешь чуть более, чем ничего.

А> Ну ну. Посмешил.

А как иначе назвать то, что мы видим выше по обсуждению?

А>>> Кстати да, ast:visit таки очень неплохой пример преимуществ метапрограммирования.

T>>Чем он хуже generic с оптимизациями?
А> Компактнее.

Сравни код на generic с кодом на ast:visit.

А> Услойчивее к изменениям структуры.


Приведи примеры большей устойчивости.

А> Лучше подходит для тривиальных преобразований.


Ой.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[31]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 20.08.09 16:59
Оценка: 2 (1)
Здравствуйте, thesz, Вы писали:

T>>>А для меня твой вариант интересен исключительно в развлекательных целях. Проблемы я буду решать по-другому.

А>> Это существенно ограничивает круг проблем, которые ты способен решать (за приемлемое время).

T>Да ты чо!


Да-да.

T>Давай возьмём любое приложение и посмотрим, как много там можно приложить метапрограммирования.


Сложно найти такую задачу, которая от метапрограммирования не выигрывала бы. Поскольку метапрограммирование — лучший способ реализации language oriented programming, да да, именно метапрограммирование, а не ФВП.

А>> Ну, твоего кода я вообще не видел, но представление имею, как он может выглядеть. Человек, принципиально не понимающий Лиспа в частности и метапрограммирования вообще, может та-акого понаписать...


T>Наверное, что-то простое и наиболее подходящее к проблеме?


Вот про "простое" не поверю. Простое — это прямолинейное. Ты же ищешь сложные обходные пути, лишь бы оно "идиоматично" получилось.

Т> Уж точно без метапрограммирования там, где оно не нужно. И с метапрограммированием там, где нужно.


Да не знаешь ты, где оно нужно, к сожалению.

T>Производительность — см. другие способы ускорения программ.


Другие способы слишком дорогостоящие. Дешевле кодогенерации ничего пока не придумали.

T>А то, что не решает поставленной задачи, так это задача так поставлена, что её хрен решить.


Что ж ты мне мозги пудришь, про эти ассоциированные типы? Я же сразу сказал, что они не являются ни разу решением этой задачи.

T>>>Я так не думаю. Наоборот, задача содержит столько ограничений, что её решение будет наиболее ограниченным.

А>> Я уже понял, что ты абсолютно не понимаешь, что такое метапрограммирование.

T>В свете количества твоих ошибок это выглядит, скорее, как комплимент.


?!? Ошибок я не делал. Я выразил сомнение в надёжности reify — и тут же признал, что был неправ. Во всём остальном я ни разу не ошибся. Ты видишь то, что хочешь видить, а не что есть на самом деле.

T>>>Я на ассемблере с макросами (ТурбоАссемблер) написал не менее миллиона строк. И макросов там было много, процентов 5.

А>> Да какое это на фиг метапрограммирование? Это фигня, банальные макры.

T>CREATE..DOES> банальные макры?


Именно, именно. Банальнее некуда. У модели Форта есть очень серьёзные ограничения, делающие метапрограммирование на нём неоправданно сложным.

T>Там рассказано, как парой килобайт кода на Форте сделать Лисп, да со скобочками, а не просто так, а на Лиспе потом написать Пролог, на котором формулировать правила экспертных систем.


Да делал я Лисп на Форте. Все делали. И Форт на Macro32 делал, и Лисп на Форте, и Пролог на Лиспе... Только фигня это всё. Неоправданно сложно. Моментальный качественный переход вместо итеративного, инкрементального роста. Ну а Пролог на Лиспе — это уже да, это легко и просто. Когда нормальное метапрограммирование есть, генерить WAM можно элементарно. Правда, Пролог туп, компиляцию в WAM можно и средствами Форта сделать довольно таки адекватно и читабельно, хоть и не сравнимо с простотой реализации того же самого средствами Лиспа.

T>>>Forth и ассемблер.

А>> Да уж... Даже не смешно.

T>Как я понимаю, ты и про Форт не очень много знаешь.


Неверно понимаешь. Точнее, совсем ни фига не понимаешь.

T>>>Если ты не любишь ограничения, то зачем ты себя сразу ограничил в формулировке задачи?

А>> Потому что этот подход снимает вообще любые ограничения, сразу. Это способ избавиться от ограничений навсегда.

T>Про фальсифицируемость и Карла Поппера ты не слышал, нет?


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

T>Вызов instance тебе даст упрощение, которое будет проводиться при вызове того, чему присвоили $(thlisp ...).


Я так и понял, что ты даже не осилил понять того моего примитивного кода. Твоё решение даже так, как ты говоришь, работать не будет. Вставь там pprint, посмотри, что на выходе $(thlisp ...).

T> Вместо вызова макроопределения (macroname macroArgs) (на Хаскеле LCon macroName macroArgs) per se ты должен сделать THLisp.expand (LApp Macro_macroname macroArgs). Macro_macroname раскроет своё тело с подстановкой macroArgs в момент обращения к значению.


На кой мне эти списки во время исполнения? Макры должны раскрываться во время компиляции. Точка. Другие решения — извращение, неоправданное и нелепое.

А>> Ты, похоже, не понял, в какой момент отрабатывает expand...


T>В момент обращения.


Это уже тогда не expand, это фигня какая-то.

T>>>Идея, я думаю, ясна.

А>> Всё ещё не ясна.

T>Здесь я умываю руки.


Мне не ясна не идея, а, скажем так, твоё странное упорство в её отстаивании.

T>Я и так рассказал много больше, чем услышал. Хотя надеялся на обратное, тем более, что начальное заявление было твоим
Автор:
Дата: 12.08.09
(надеюсь, что твоим, а то вас анонимов не поймёшь).


Что именно хотел? Компилятор той VM на TH и на Лиспе? До этого у меня руки ещё не дошли. Сделаю, как время будет. Вот может сегодня вечером и сделаю.

T>А про такой вариант
Автор: geniepro
Дата: 13.02.09
?


T>Может, что интересное для себя извлечёшь.


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

T>>>И почему конкретно?

А>> Потому, что не всё можно параллелить.

T>То, что работает долго, обычно можно.


А вот теперь уже моя очередь умывать руки... Даже не представляю, что на такую чушь можно возразить.

T>>>Кодогенерация.

А>> Которая является частным случаем метапрограммирования.

T>Или наоборот.


См. определение метапрограммирования.

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


T>Ты, видимо, не знаешь, что верткие хоккеисты, разящие боксёры, быстрые спринтеры и даже молниеносный Брюс Ли — все они развивали и развивают мышечную силу.


До определённого предела. Если перекачаешься, то потом гибкость вернуть уже очень сложно.

T>Если возвращаться к теме мышления, то ум прямо пропорционален скорости перебора вариантов (скорости решения простых задач). Умение выдать быстрое и неожиданное решение говорит именно об уме, поэтому не стоит себя принижать.


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

T>О практическом уме говорит способность выдать правильное и применимое решение. Очень показательно отсутствие этих двух пунктах в твоём параграфе выше.


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

T>>>А Лисп не настолько сложный, чтобы его не понять. Как и метапрограммирование.

А>> Именно. Всё очень просто. Но ты не понимаешь — поскольку мыслишь в совершенно иных категориях.

T>Я понимаю.


Нет, не понимаешь. Иначе бы не городил expand, который раскрывается при первом вызове.

T>Но я понимаю, также, что не все задачи требуют своего ЯП с настолько своим синтаксисом, что надо столь сильно изощряться.


Столь сильно изощряться приходится только в TH. По причине его неприспособленности к таким вещам. На Лиспе изощряться не приходится.

T>На моей памяти таких задач раз, два и обчёлся.


Ну повезло, значит.

T>Мне бы хотелось, по результатам этой дискуссии, твоего признания, что ты не всё понимаешь в Хаскеле, Форте и других языках.


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

T>Из этого будет следовать вывод, что твой текущий подход не самый лучший, но я его опущу.


Для TH — конечно не самый лучший. Потому как TH крив. А я хочу его улучшить — так, чтобы в Хаскелле, кроме прочих, работал бы ещё и этот подход.

T>>> Я подозреваю, более того, что количество ошибок в твоём коде достаточно высоко, а исправление трудоёмко.

А>> Абсолютно неверный вывод.

T>Это не только мой вывод, это вывод бывших лисперов.


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

Показать, например, реализацию pattern matching в Лиспе, сделанную таким способом? Или, например, list comprehensions? Или реализацию инфиксного синтаксиса?

T>Ты, вон, приведи код функции, что не даёт подать на свой вход код с нераскрытыми макросами.


Это вообще как? Макросы раскрываются компилятором, какой такой вообще "код" может быть подан на вход функции в рантайме?

T>Строгая типизация была придумана для оптимизаций, а сейчас используется для структурирования программ.


Интересная точка зрения. Пруфлинк? С Лукой Карделли я знаком, он таких странностей не говорил и не писал. Кто больший авторитет в типах — я не в курсе.

T>Чем для структурирования программ пользуешься ты?


Семантикой. Я довожу идею language oriented programming до абсолюта — каждой задаче свой язык, всегда. Как бы мелка задача не была. Системы типов — лишь частный случай такого подхода.

А>>>> Нет, оптимизация в данном случае совершенно не при чём. Важна семантика.

T>>>Тогда генерируй Лисп и раскрывай по необходимости. Лениво, так сказать.
А>> Второе условие — код надо скрыть.

T>У тебя условия появляются по ходу дискуссии.


Да ну? Я это условие сформулировал в самом начале ещё, читай внимательнее. Я отвечал на вопрос, почему нельзя код динамически генерить, и сказал, что это минимально приемлемая защита от reverse engineering.

T>Это верный признак того, что мой оппонент пытается выставить меня не дураком, нет, но человеком заведомо не умнее себя.


Скорее это признак того, что кое-кто читает не очень внимательно.

T>"А вот тебе ещё условие. А вот посмотрим, как ты с ним справишься. Ага, не справился! Вот и я не могу. Да ты, оказывается, не умней меня."


Условие, что весь код генерится статически и во время компиляции было выскзано в самом начале. Далее следовали объяснения, почему такое условие вводится — но они, собственно, и не нужны. Ты всё время пытаешься условие расширить, и решить другую задачу. Мне же другие решения не интересны, я их и так прекрасно знаю.

T> Идиоматический подход в Хаскеле таков: сперва надо получить хоть какую-то реализацию просто на Хаскеле, затем постепенно надо переносить её в TH или комбинаторы, вплоть до получения необходимой формы.


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

T>Изначально у тебя отдельно стоящего Лиспа не было. Поэтому и всех условий не было видно.


Ну почему же — с начала я сделал компилятор Лиспа без макр. И после этого уже поставил задачу — в рамках конкретно этого подхода добавить defmacro.

T> Поэтому ты и топчешься на месте, путаясь в TH, а не в переносе уже готовой функциональности в средства TH.


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

А>> Те, кто про него знают, Хаскеллем не пользуются.


T>То есть, ты Хаскелем не пользуешься?


Пользуюсь не эксклюзивно. Там, где мне нужно метапрограммирование, я им не пользуюсь.

T>Ты не читаешь свои комментарии.


Не буквоедствуй. Я вполне нормально объяснил, почему у TH так мало пользователей и практических применений.

А>>>> Кстати да, ast:visit таки очень неплохой пример преимуществ метапрограммирования.

T>>>Чем он хуже generic с оптимизациями?
А>> Компактнее.

T>Сравни код на generic с кодом на ast:visit.


Уже ранее приводившийся тут код для lambda lifting и обработки lexical scope — заведомо и очевидно компактнее.

А>> Услойчивее к изменениям структуры.


T>Приведи примеры большей устойчивости.


Измени определение AST для той самой задачи про lambda lifting, и посмотри.

А>> Лучше подходит для тривиальных преобразований.


T>Ой.


Я же объяснил, почему нужны именно тривиальные преобразования. И почему они должны быть простыми и читабельными.
Re[32]: Как написать виртуальную машину на LISP
От: frontsquat  
Дата: 20.08.09 18:06
Оценка: +1
Здравствуйте, Аноним, Вы писали:

А> Даже среди лисперов очень мало тех, кто умеет пользоваться метапрограммированием. Большинство делают одну и ту же ошибку — чрезмерно сложное преобразование в один проход. Почти никто не понимает истинного подхода — инкрементального метапрограммирования, с тривиальными преобразованиями на каждом этапе.


А> Показать, например, реализацию pattern matching в Лиспе, сделанную таким способом? Или, например, list comprehensions? Или реализацию инфиксного синтаксиса?


Покажи, как время будет.
Re[32]: Как написать виртуальную машину на LISP
От: thesz Россия http://thesz.livejournal.com
Дата: 20.08.09 21:33
Оценка:
Здравствуйте, Аноним, Вы писали:

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


T>>Давай возьмём любое приложение и посмотрим, как много там можно приложить метапрограммирования.

А> Сложно найти такую задачу, которая от метапрограммирования не выигрывала бы. Поскольку метапрограммирование — лучший способ реализации language oriented programming, да да, именно метапрограммирование, а не ФВП.

То-то весь более-менее прогрессивный мир стремится в область зависимых типов...

А>>> Ну, твоего кода я вообще не видел, но представление имею, как он может выглядеть. Человек, принципиально не понимающий Лиспа в частности и метапрограммирования вообще, может та-акого понаписать...

T>>Наверное, что-то простое и наиболее подходящее к проблеме?
А> Вот про "простое" не поверю. Простое — это прямолинейное. Ты же ищешь сложные обходные пути, лишь бы оно "идиоматично" получилось.

An idiom is a phrase whose meaning cannot be determined by the literal definition of the phrase itself, but refers instead to a figurative meaning that is known only through common use. (C) Wikipedia


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

Иными словами, наиболее прямое решение.

Например, не стоит писать компилирующий вариант Лиспа на Си с использованием тамошнего метапрограммирования.

Т>> Уж точно без метапрограммирования там, где оно не нужно. И с метапрограммированием там, где нужно.

А> Да не знаешь ты, где оно нужно, к сожалению.

Без указаний, что и где я не знаю, это бессмысленное заявление. Особенно с учётом широты термина "метапрограммирование".

T>>А то, что не решает поставленной задачи, так это задача так поставлена, что её хрен решить.

А> Что ж ты мне мозги пудришь, про эти ассоциированные типы? Я же сразу сказал, что они не являются ни разу решением этой задачи.

А почему они не являются решением этой задачи? Что мешает их использовать?

T>>>>Я так не думаю. Наоборот, задача содержит столько ограничений, что её решение будет наиболее ограниченным.

А>>> Я уже понял, что ты абсолютно не понимаешь, что такое метапрограммирование.
T>>В свете количества твоих ошибок это выглядит, скорее, как комплимент.
А> ?!? Ошибок я не делал. Я выразил сомнение в надёжности reify — и тут же признал, что был неправ. Во всём остальном я ни разу не ошибся. Ты видишь то, что хочешь видить, а не что есть на самом деле.

Либо ты не хочешь видеть того, что пошатнёт тебя в твоих глазах.

Смотри, ты сказал, что reify неприменим по такой-то причине, исправился и продолжил утверждать, что Template Haskell неприменим. Вместо поиска решения с использованием, возможно, других средств Хаскеля.

И продолжал упорствовать, вместо того, чтобы попробовать ассоциированные типы и применить их по месту.

T>>>>Я на ассемблере с макросами (ТурбоАссемблер) написал не менее миллиона строк. И макросов там было много, процентов 5.

А>>> Да какое это на фиг метапрограммирование? Это фигня, банальные макры.
T>>CREATE..DOES> банальные макры?
А> Именно, именно. Банальнее некуда.

А семантику пары CREATE..DOES> не расскажешь ли?

А> У модели Форта есть очень серьёзные ограничения, делающие метапрограммирование на нём неоправданно сложным.


И какие же?

T>>>>Forth и ассемблер.

А>>> Да уж... Даже не смешно.
T>>Как я понимаю, ты и про Форт не очень много знаешь.
А> Неверно понимаешь. Точнее, совсем ни фига не понимаешь.

Тут какая ситуация.

Я и другие говорю, что в Форте метапрограммирование есть. Мощное, хорошее метапрограммирование.

Ты говоришь, что его там нет.

Я бы согласился с тобой, если бы другие говорили так же, как ты.

Здесь всё та же ситуация, когда ты идёшь в ногу, а все не в ногу.

T>>>>Если ты не любишь ограничения, то зачем ты себя сразу ограничил в формулировке задачи?

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

Намекну. Если инструмент не имеет чётко очерченной области применения, если нельзя придумать способа применения, который приводит к снижению производительности, то этот инструмент имеет божественные качества. Сиречь, является объектом религиозного поклонения, а вдумчивого применения по месту.

T>>Вызов instance тебе даст упрощение, которое будет проводиться при вызове того, чему присвоили $(thlisp ...).

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

Почему?

А> Вставь там pprint, посмотри, что на выходе $(thlisp ...).


Если я правильно понимаю, изменения минимальны.

Измени сигнатуру чего у меня там было в классе с Lisp ty на IO (Lisp ty), и делов. И expand тоже надо будет поменять.

Если это не проходит, то почему?

T>> Вместо вызова макроопределения (macroname macroArgs) (на Хаскеле LCon macroName macroArgs) per se ты должен сделать THLisp.expand (LApp Macro_macroname macroArgs). Macro_macroname раскроет своё тело с подстановкой macroArgs в момент обращения к значению.

А> На кой мне эти списки во время исполнения? Макры должны раскрываться во время компиляции. Точка. Другие решения — извращение, неоправданное и нелепое.

Ну, уговорил.

Заведи IORef с макросами.

import System.IO
import Data.IORef
import System.IO.Unsafe

{-# NOINLINE topDecls #-}
topDecls :: IORef [String]
topDecls = unsafePerformIO $ newIORef []

compile_top :: LispTop -> DecQ
compile_top (LAdefun nm args body) = do
    loc <- location
    runIO $ modifyIORef topDecls (\s -> (loc_module loc++'.':nm):s)
    funD (mkName ("lisp_" ++ nm))
         [(clause [(listP (map (\n -> varP (mkName n)) args))]
                      (normalB (compile_expr body)) [])]

thAllTopDecls :: ExpQ
thAllTopDecls = do
    allDecls <- runIO $ readIORef topDecls
    return $ LitE $ StringL $ show allDecls

-- там, где main:
main = do
   ...
   putStrLn $(thAllTopDecls) -- покажет ["Main.fact"]


В энтот IORef можно запендюривать всё, что душе угодно.

Например, код макросов супротив их имени.

А>>> Ты, похоже, не понял, в какой момент отрабатывает expand...

T>>В момент обращения.
А> Это уже тогда не expand, это фигня какая-то.

Чем отличается?

T>>>>Идея, я думаю, ясна.

А>>> Всё ещё не ясна.
T>>Здесь я умываю руки.
А> Мне не ясна не идея, а, скажем так, твоё странное упорство в её отстаивании.

Из нас двоих хоть какие-то мысли в направлении решения тобой поставленной задачи выражаю я один.

Ты просто упорствуешь в тезисе "метапрограммирование — это круто!" а я предлагаю решения.

По-моему, я круче и поэтому метапрограммирование — отстой.

T>>Я и так рассказал много больше, чем услышал. Хотя надеялся на обратное, тем более, что начальное заявление было твоим
Автор:
Дата: 12.08.09
(надеюсь, что твоим, а то вас анонимов не поймёшь).

А> Что именно хотел? Компилятор той VM на TH и на Лиспе? До этого у меня руки ещё не дошли. Сделаю, как время будет. Вот может сегодня вечером и сделаю.

Достаточно компилятора Лиспа на TH. С макросами!

Хотя с идеей насчёт IORef, что выше, проблем уже не должно возникнуть.

T>>>>И почему конкретно?

А>>> Потому, что не всё можно параллелить.
T>>То, что работает долго, обычно можно.
А> А вот теперь уже моя очередь умывать руки... Даже не представляю, что на такую чушь можно возразить.

Если это не так, то приведи опровергающий пример.

Медленно работает алгоритм, что по дизайну работает медленно: подсчёт MD5, например. А вот перебор столкновений для MD5 уже можно сделать быстрым.

BTW, я занимался проектированием параллельных железок (процесоров) и созданием алгоритмов автоматического распараллеливания для них. Я знаю, о чём говорю.

T>>>>Кодогенерация.

А>>> Которая является частным случаем метапрограммирования.
T>>Или наоборот.
А> См. определение метапрограммирования.

Приведи ссылку. В английской википедии толкование расширительное, пересекается с компиляцией.

compiler is a computer program (or set of programs) that transforms source code written in a computer language (the source language) into another computer language (the target language, often having a binary form known as object code).

Metaprogramming is the writing of computer programs that write or manipulate other programs (or themselves) as their data, or that do part of the work at compile time that would otherwise be done at runtime.


T>>Если возвращаться к теме мышления, то ум прямо пропорционален скорости перебора вариантов (скорости решения простых задач). Умение выдать быстрое и неожиданное решение говорит именно об уме, поэтому не стоит себя принижать.


T>>О практическом уме говорит способность выдать правильное и применимое решение. Очень показательно отсутствие этих двух пунктах в твоём параграфе выше.

А> Я говорю о ситуациях, когда никакого другого решения, кроме неожиданного и нелепого, нет вообще. Про "нерешаемые" задачи.

Приведи пример.

T>>>>А Лисп не настолько сложный, чтобы его не понять. Как и метапрограммирование.

А>>> Именно. Всё очень просто. Но ты не понимаешь — поскольку мыслишь в совершенно иных категориях.
T>>Я понимаю.
А> Нет, не понимаешь. Иначе бы не городил expand, который раскрывается при первом вызове.

Что сейчас скажешь?

T>>Но я понимаю, также, что не все задачи требуют своего ЯП с настолько своим синтаксисом, что надо столь сильно изощряться.

А> Столь сильно изощряться приходится только в TH. По причине его неприспособленности к таким вещам. На Лиспе изощряться не приходится.

Решая повседневные задачи, мне не приходится изощряться ни как на Лиспе, ни как-нибудь ещё. Я их просто решаю.

T>>Мне бы хотелось, по результатам этой дискуссии, твоего признания, что ты не всё понимаешь в Хаскеле, Форте и других языках.

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

Так проще.

А если что, то rewrite rules, да ассоциированные типы.

T>>Из этого будет следовать вывод, что твой текущий подход не самый лучший, но я его опущу.

А> Для TH — конечно не самый лучший. Потому как TH крив. А я хочу его улучшить — так, чтобы в Хаскелле, кроме прочих, работал бы ещё и этот подход.

Что сейчас скажешь?

T>>>> Я подозреваю, более того, что количество ошибок в твоём коде достаточно высоко, а исправление трудоёмко.

А>>> Абсолютно неверный вывод.
T>>Это не только мой вывод, это вывод бывших лисперов.
А> Даже среди лисперов очень мало тех, кто умеет пользоваться метапрограммированием. Большинство делают одну и ту же ошибку — чрезмерно сложное преобразование в один проход. Почти никто не понимает истинного подхода — инкрементального метапрограммирования, с тривиальными преобразованиями на каждом этапе.

Это точно религия, прошу прощения за мой французский.

А> Показать, например, реализацию pattern matching в Лиспе, сделанную таким способом? Или, например, list comprehensions? Или реализацию инфиксного синтаксиса?


Синтаксисом меня не напугать.

Покажи, лучше, GADT, type classes, да type families с выводом типов.

T>>Ты, вон, приведи код функции, что не даёт подать на свой вход код с нераскрытыми макросами.

А> Это вообще как? Макросы раскрываются компилятором, какой такой вообще "код" может быть подан на вход функции в рантайме?

Ну, хорошо.

Покажи функцию, что не даёт подать на вход AST с сохранившимися let и where конструкциями.

T>>Строгая типизация была придумана для оптимизаций, а сейчас используется для структурирования программ.

А> Интересная точка зрения. Пруфлинк? С Лукой Карделли я знаком, он таких странностей не говорил и не писал. Кто больший авторитет в типах — я не в курсе.

Последнее где-то в блогах обнаружил.

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

Типы в Фортране появились как раз из-за скорости работы, AFAIK.

T>>Чем для структурирования программ пользуешься ты?

А> Семантикой. Я довожу идею language oriented programming до абсолюта — каждой задаче свой язык, всегда. Как бы мелка задача не была. Системы типов — лишь частный случай такого подхода.

Приведи пример.

Можно ли попросить тебя совместить описание пользовательского интерфейса и ограничений на размеры и положение элементов?

Я это на зипперах делаю. Получается умеренно плохо.

А>>>>> Нет, оптимизация в данном случае совершенно не при чём. Важна семантика.

T>>>>Тогда генерируй Лисп и раскрывай по необходимости. Лениво, так сказать.
А>>> Второе условие — код надо скрыть.
T>>У тебя условия появляются по ходу дискуссии.
А> Да ну? Я это условие сформулировал в самом начале ещё, читай внимательнее. Я отвечал на вопрос, почему нельзя код динамически генерить, и сказал, что это минимально приемлемая защита от reverse engineering.

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

Поэтому моя вера в reverse engineering тверда и непоколебима.

T>> Поэтому ты и топчешься на месте, путаясь в TH, а не в переносе уже готовой функциональности в средства TH.

А> Да неверный это подход, переносить динамику в статику. Именно таким походом вся прелесть метапрограммирования и гробится. Теперь понятно, почему ты настолько метапрограммирование недооцениваешь.

Я жду, когда в Agda2 или в Epigram появится метапрограммирование. Вот там это будет круто просто невероятно, как.

Лисп мне неинтересен потому, что на нём сложно сделать суперанализ и насыщение равенствами. Без проверки типов я уже напрограммировался, хватит.

А>>>>> Кстати да, ast:visit таки очень неплохой пример преимуществ метапрограммирования.

T>>>>Чем он хуже generic с оптимизациями?
А>>> Компактнее.
T>>Сравни код на generic с кодом на ast:visit.
А> Уже ранее приводившийся тут код для lambda lifting и обработки lexical scope — заведомо и очевидно компактнее.

Здесь этого не приводилось.

Вот, что было:

Надо написать преобразование этого AST, такое, что каждое локально введённое имя будет заменяться на сгенерённый уникальный идентификатор.


{-# LANGUAGE DeriveDataTypeable #-}
import Data.Data
import Data.Generics
import Data.Maybe

import Control.Monad.State
import Control.Monad.Error

data E = Const Int
    | Var String
    | App E E
    | Let String E E
    | Abs String E
    deriving (Typeable,Data,Show)

type WalkM a = StateT (Int,[(String,String)]) (Either String) a

testE = Let "x" (App (Var "a") (Var "b")) (App (App (Var "+") (Var "x")) (Var "y"))

inventVar :: WalkM String
inventVar = do
    (cnt,trans) <- get
    put (cnt+1,trans)
    return $ "__temp__"++show cnt

-------------------------
-- логика бегинз
changeE' :: E -> WalkM E
changeE' (Let ident e1 e2) = do
    ident' <- inventVar
    modify $ \(cnt,trans) -> (cnt,(ident,ident'):trans)
    e2' <- changeE e2
    modify $ \(cnt,trans) -> (cnt,filter ((/=ident) . fst) trans)
    return $ Let ident' e1 e2'
changeE' (Var id) = do
    id' <- liftM (fromMaybe id . lookup id . snd) get
    return $ Var id'
changeE' _ = throwError "..."
-- логика ендз
-------------------------

changeE :: E -> WalkM E
changeE e = everywhereM (somewhere (mkM changeE')) e

test = runStateT (changeE testE) (0,[])
-- *Main> test
-- Right (Let "__temp__0" (App (Var "a") (Var "b")) (App (App (Var "+") (Var "__temp__0")) (Var "y")),(1,[]))


А>>> Услойчивее к изменениям структуры.

T>>Приведи примеры большей устойчивости.
А> Измени определение AST для той самой задачи про lambda lifting, и посмотри.

Где та самая задача про "lambda lifting"?

Для решения выше ты можешь добавить что-то и менять отличные от Let и Var конструкторы.

А>>> Лучше подходит для тривиальных преобразований.

T>>Ой.
А> Я же объяснил, почему нужны именно тривиальные преобразования. И почему они должны быть простыми и читабельными.

А нельзя ли пользоваться сложными преобразованиями, если есть поддержка системы типов? Если нельзя, то почему?
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[32]: Как написать виртуальную машину на LISP
От: VoidEx  
Дата: 20.08.09 21:49
Оценка: +2
Здравствуйте, Аноним, Вы писали:

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


Я не слышал. Гугл сходу не ответил. Не подскажите ссылок, или вкратце, что за свойства?

А> Показать, например, реализацию pattern matching в Лиспе, сделанную таким способом? Или, например, list comprehensions? Или реализацию инфиксного синтаксиса?


Было бы интересно.

А> Угу, плохие лисперы тоже так макры пишут. Тут ещё как-то видео смешное на эту тему пробегало, лучшая антиреклама Лиспу, по моему. Это в корне неверный подход к метапрограммирвоанию.


Тут? Не сохранилось ссылки или хотя бы как искать?
Re[33]: Как написать виртуальную машину на LISP
От: VoidEx  
Дата: 20.08.09 22:06
Оценка:
Здравствуйте, thesz, Вы писали:

T>В энтот IORef можно запендюривать всё, что душе угодно.


T>Например, код макросов супротив их имени.


The runIO function lets you run an I/O computation in the Q monad. Take care: you are guaranteed the ordering of calls to runIO within a single Q computation, but not about the order in which splices are run.


Не помешает ли? Я так понимаю, несколько вызовов thlisp запихнут определения в произвольном порядке.
Re[34]: Как написать виртуальную машину на LISP
От: thesz Россия http://thesz.livejournal.com
Дата: 21.08.09 06:43
Оценка:
Здравствуйте, VoidEx, Вы писали:

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


T>>В энтот IORef можно запендюривать всё, что душе угодно.


T>>Например, код макросов супротив их имени.


VE>

VE>The runIO function lets you run an I/O computation in the Q monad. Take care: you are guaranteed the ordering of calls to runIO within a single Q computation, but not about the order in which splices are run.


VE>Не помешает ли? Я так понимаю, несколько вызовов thlisp запихнут определения в произвольном порядке.


Если ограничиться вызовом макросов, только определённых в другом модуле, то помешать не должно. Они все окажутся в IORef перед вызовом любого splice из нашего текущего модуля.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[33]: Как написать виртуальную машину на LISP
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 21.08.09 08:45
Оценка: 4 (1)
Здравствуйте, VoidEx, Вы писали:

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

VE>Я не слышал. Гугл сходу не ответил. Не подскажите ссылок, или вкратце, что за свойства?

Ищи по словам "колмогоровская сложность".
Re[33]: Как написать виртуальную машину на LISP
От: Курилка Россия http://kirya.narod.ru/
Дата: 21.08.09 09:18
Оценка:
Здравствуйте, VoidEx, Вы писали:

VE>Здравствуйте, Аноним, Вы писали:


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


VE>Я не слышал. Гугл сходу не ответил. Не подскажите ссылок, или вкратце, что за свойства?


Осмелюсь предположить про статью на вики
Re[33]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 21.08.09 11:08
Оценка:
Здравствуйте, thesz, Вы писали:

А>> Сложно найти такую задачу, которая от метапрограммирования не выигрывала бы. Поскольку метапрограммирование — лучший способ реализации language oriented programming, да да, именно метапрограммирование, а не ФВП.


T>То-то весь более-менее прогрессивный мир стремится в область зависимых типов...


Причём, заметь, началось это всё с лисперов (Axiom). Ты явно ослеплён этими своими типами. Такая примитивная хреновина — а ты их за панацею считаешь.

А>> Вот про "простое" не поверю. Простое — это прямолинейное. Ты же ищешь сложные обходные пути, лишь бы оно "идиоматично" получилось.


T>

An idiom is a phrase whose meaning cannot be determined by the literal definition of the phrase itself, but refers instead to a figurative meaning that is known only through common use. (C) Wikipedia


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


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

T>Иными словами, наиболее прямое решение.


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

T> Например, не стоит писать компилирующий вариант Лиспа на Си с использованием тамошнего метапрограммирования.


Не стоит, да.

T>>>А то, что не решает поставленной задачи, так это задача так поставлена, что её хрен решить.

А>> Что ж ты мне мозги пудришь, про эти ассоциированные типы? Я же сразу сказал, что они не являются ни разу решением этой задачи.

T>А почему они не являются решением этой задачи? Что мешает их использовать?


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


T>Либо ты не хочешь видеть того, что пошатнёт тебя в твоих глазах.


Знаешь, в отличии от некоторых, через слово кричащих о своём зашкаливающем IQ, я абсолютно не гордый. Я обычный, нормальный дурак, решающий обычную, нормальную задачу. И мне интересно её решение в рамках вполне конкретного подхода. Мне наплевать на другие варианты решения, я их и без тебя знаю. Мне важно найти корректное применение именно 100% статическому метапрограммированию в Хаскелле, а всё остальное не колышет. Так что перестань переводить разговор на нерелевантные темы, пожалуйста. У меня мало времени, и я не хочу его тратить на обсуждение неинтересных мне тем.

T> Смотри, ты сказал, что reify неприменим по такой-то причине, исправился и продолжил утверждать, что Template Haskell неприменим. Вместо поиска решения с использованием, возможно, других средств Хаскеля.


Да не нужны мне другие средства Хаскелля. Мне интересно решить задачу конкретно этим способом. А всякое тупое барахло на комбинаторах я сделать всегда успею.

T>И продолжал упорствовать, вместо того, чтобы попробовать ассоциированные типы и применить их по месту.


Опять ты за своё. Не "по месту" тут динамические решения, абсолютно. В этой задаче они меня не интересуют в принципе.

А>> Именно, именно. Банальнее некуда.


T>А семантику пары CREATE..DOES> не расскажешь ли?


Дурная у них семантика — CREATE заводит новую запись с словаре, а всё, что между DOES> и ; будет во время компиляции подставлено в каждом приложении определённого CREATE слова. Макра банальнейшая.

Упражнение на вывих мозга — реализовать lexically scoped macros на этом безобразии. Хи хи.

А>> У модели Форта есть очень серьёзные ограничения, делающие метапрограммирование на нём неоправданно сложным.


T>И какие же?


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

T>Я и другие говорю, что в Форте метапрограммирование есть. Мощное, хорошее метапрограммирование.


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

T>Ты говоришь, что его там нет.


Я говорю, что это слишком примитивно, чтобы быть настоящим метапрограммированием.

T>Я бы согласился с тобой, если бы другие говорили так же, как ты.


Большинство лисперов со мной согласятся.

T>Здесь всё та же ситуация, когда ты идёшь в ногу, а все не в ногу.


Вся секта идёт не в ногу, ага. А что мне до сектантов? Я из этой палаты выписался давно.

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


T>Намекну. Если инструмент не имеет чётко очерченной области применения, если нельзя придумать способа применения, который приводит к снижению производительности, то этот инструмент имеет божественные качества. Сиречь, является объектом религиозного поклонения, а вдумчивого применения по месту.


Ясно. Не знаешь и не понимаешь основ алгоритмической теории информации. Я же намекнул на очень конкретную область применения.

T>>>Вызов instance тебе даст упрощение, которое будет проводиться при вызове того, чему присвоили $(thlisp ...).

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

T>Почему?


Потому, что в рантайме у нас уже просто нет компилятора Лиспа. Совсем. И то, что макра раскроется в рантайме, нам ничем не поможет.

А>> Вставь там pprint, посмотри, что на выходе $(thlisp ...).


T>Если я правильно понимаю, изменения минимальны.


Неправильно.

T>Измени сигнатуру чего у меня там было в классе с Lisp ty на IO (Lisp ty), и делов. И expand тоже надо будет поменять.


T>Если это не проходит, то почему?


Потому, что после expand структуры LispV проходят через expr2AST, а замет sanitiseAST (а ему нужен полный код выражения, со всеми уже в статике раскрытыми макрами — поскольку в более сложном варианте именно тут должны делаться оптимизации и проводиться проверки корректности). Результат этого безобразия подаётся compile_expr :: LispAst -> Q Exp; Прошу внимательнее посмотреть на эту сигнатуру. Тут просто нет места уже никаким LispV, за исключением константных списков.

Надо ли говорить, что в рантайме у нас compile_expr работать не будет вообще? И это кстати правильно и я это полностью поддерживаю, это в рамках идеологии TH.

T>Заведи IORef с макросами.


Блин. И эти люди запрещают мне ковыряться в носу?!? Я раз двадцать всего лишь сказал, что мне нужно православное решение. Что-то типа runMeta внутри монады Q. Чисто функциональненько, без всяких там императивных грязных хаков. С хаками я и так сделал, это не интересно. Я то предлагаю тривиальную модификацию TH, которая позволит такие вещи делать чистым и безопасным способом, блин.

T>topDecls = unsafePerformIO $ newIORef []


Нда... И после этого кое кто боится, что рефлексия может оказаться малость нетипобезопасной. Кто не параноик, я не параноик?!?

T>В энтот IORef можно запендюривать всё, что душе угодно.


Угу. А толку то? Это неправославно.

T>Например, код макросов супротив их имени.


Так и делаю. Но это очень некрасиво.

А>> Это уже тогда не expand, это фигня какая-то.


T>Чем отличается?


Тем, что compile_expr уже "в момент обращения" работать не будет, придётся содержать ещё и вторую версию компилятора, который генерил бы код на комбинаторах.

T>Из нас двоих хоть какие-то мысли в направлении решения тобой поставленной задачи выражаю я один.


Да нет, ты всё время предлагаешь мне порешать другую задачу, которая мне не интересна. Решения задачи о православной рефлексии внутри монады Q ты не нашел.

T>По-моему, я круче и поэтому метапрограммирование — отстой.


Да нет, не круче. Ты Лиспа не знаешь. Как может быть крутым кто-то, кто не знает кошегъного пгавославного Лиспа?

А>> Что именно хотел? Компилятор той VM на TH и на Лиспе? До этого у меня руки ещё не дошли. Сделаю, как время будет. Вот может сегодня вечером и сделаю.


T>Достаточно компилятора Лиспа на TH. С макросами!


Я не обещал с макросами. Я обещал простенький. А с макросами он православным не получается.

T>Хотя с идеей насчёт IORef, что выше, проблем уже не должно возникнуть.


Ну и где тут православность?

А>> А вот теперь уже моя очередь умывать руки... Даже не представляю, что на такую чушь можно возразить.


T>Если это не так, то приведи опровергающий пример.


Посчитай мне параллельно ряд Фибоначчи. Вообще любая задача, в которой следующая итерация зависит от результата предыдущей, параллелизации не поддаётся принципиально.

T>BTW, я занимался проектированием параллельных железок (процесоров) и созданием алгоритмов автоматического распараллеливания для них. Я знаю, о чём говорю.


Да хорош уже понтоваться, это надоедать начинает. Я вон тоже когда-то давно на Occam-е писал под инмосы. И кластеры строил, для числомолотильни на MPI. И агентным моделированием занимался. Уж что можно распараллелить, а что не получится даже в самой смелой теории, я прекрасно знаю.

T>Приведи ссылку. В английской википедии толкование расширительное, пересекается с компиляцией.


Угу, угу. Я ж говорю — это самый общий случай. Любой процесс, результатом которого является код любого уровня, является метапрограммированием.

T>Приведи пример.


Воздержусь, на ум приходят только чрезмерно узкоспециальные задачи.

А>> Нет, не понимаешь. Иначе бы не городил expand, который раскрывается при первом вызове.


T>Что сейчас скажешь?


Что сейчас то? Ты всё ещё считаешь, что expand может работать в рантайме, с сохранением backend-а компилятора на TH? Серьёзно?

T>Решая повседневные задачи, мне не приходится изощряться ни как на Лиспе, ни как-нибудь ещё. Я их просто решаю.


На Лиспе как раз изощряться не приходится. А вот городить всякие там типы, классы, шмассы, да ещё и там, где таких терминов то в предметной области нет и не предвидится — это и есть "изощряться".

T>Так проще.


Нет, не проще.

T>А если что, то rewrite rules, да ассоциированные типы.


Не проще. Свой механизм term rewriting и своя система типов всегда будет проще и более подойдёт под задачу, чем частный и ограниченный механизм Хаскелля.

T>>>Из этого будет следовать вывод, что твой текущий подход не самый лучший, но я его опущу.

А>> Для TH — конечно не самый лучший. Потому как TH крив. А я хочу его улучшить — так, чтобы в Хаскелле, кроме прочих, работал бы ещё и этот подход.

T>Что сейчас скажешь?


Что православного решения нет, и что механизм не работает. Что мешает тогда пуститься во все тяжкие, и даже newName реализовать через runIO? И монаду Quasi вообще выкинуть за ненадобностью. А, стрёмно, да? Ну так вот и контекст так тащить — тоже стрёмно.

А>> Даже среди лисперов очень мало тех, кто умеет пользоваться метапрограммированием. Большинство делают одну и ту же ошибку — чрезмерно сложное преобразование в один проход. Почти никто не понимает истинного подхода — инкрементального метапрограммирования, с тривиальными преобразованиями на каждом этапе.


T>Это точно религия, прошу прощения за мой французский.


Нет, это метод. Который работает. Всегда и надёжно. В отличие от.

А>> Показать, например, реализацию pattern matching в Лиспе, сделанную таким способом? Или, например, list comprehensions? Или реализацию инфиксного синтаксиса?


T>Синтаксисом меня не напугать.


Не отмазывайся. Если бы в Хаскелле не было list comprehensions — как бы ты их делал? Подозреваю, что очень криво и сложно. А на Лиспе решение тривиально.

Кстати, list comprehensions это таки не "синтакис", это вполне себе семантика.

T>Покажи, лучше, GADT, type classes, да type families с выводом типов.


Простейший вариант Хиндли-Милнера я уже показывал. Любые расширения делаются точно так же, тем более что всё это делается на основе Пролога, и тут варианты развития системы типов просто безграничны. Зависимые типы для ML я делал таким образом, ничего сложного.

T>>>Ты, вон, приведи код функции, что не даёт подать на свой вход код с нераскрытыми макросами.

А>> Это вообще как? Макросы раскрываются компилятором, какой такой вообще "код" может быть подан на вход функции в рантайме?

T>Ну, хорошо.


T>Покажи функцию, что не даёт подать на вход AST с сохранившимися let и where конструкциями.


Так это другой уже AST будет. С другим типов. Кто ж позволит то, если сигнатура функции, например, AstAfterExpansion -> AstLifted, применить её к RawAst?

T>Последнее где-то в блогах обнаружил.


Ссылку, ссылку pls. Мне реально интересно.

T>Но действительно, контекст IO типа позволяет делать ввод-вывод и обычные вычисления, отсутствие этого контекста — только обычные вычисления. Сами обычные вычисления можно структурировать дальше: разборщики, преобразователи, работающие со списками и тп.


Да никто не спорит, что типы — офигенно мощный инструмент структурирования кода. Я говрю, что это не единственный инструмент, и не самый общий.

T>Типы в Фортране появились как раз из-за скорости работы, AFAIK.


Что-то не припомню такого.

T>Можно ли попросить тебя совместить описание пользовательского интерфейса и ограничений на размеры и положение элементов?


Поясни задачу. Хочешь декларативное описание UI, что-то в духе Fudgets?

А>> Да ну? Я это условие сформулировал в самом начале ещё, читай внимательнее. Я отвечал на вопрос, почему нельзя код динамически генерить, и сказал, что это минимально приемлемая защита от reverse engineering.


T> Я как-то вскрыл пароль, повешенный на программу, написанную на симуляторе процессора с одной командой.


Представь себе — пятьдесят мегабайт скриптового кода (ну, например, всякая сложная логика для CAD — лестницы там строить, трубы прокладывать, и т.п., и всё это — очень-очень дорогостоящая собственность какой либо инженерной конторы при какой либо, например, Shell). В одном случае ты их просто выдираешь в голом виде и тащиш к конкурентам, в другом случае ищешь Сергея Зефирова, который вскрывает логику каждой отдельной функции за сутки. Берёт за свою работу, ну, допустим, $1500 в сутки, и работает над этим делом, ну, эдак, лет много — каждая функция килобайт по 2-5, а кода у нас пятьдесят мегабайт без комментариев. В этом варианте злой конкурент только плюнет на всё, и пойдёт сам логику сочинять, или стухнет, и заказчик его пойдёт к той инженерной конторе, которая этой логикой владеет.

T> С самомодифицирующимся кодом. Примерно за сутки. В архивах PVT.CRACK должно быть письмо.


Да все в детстве такой фигнёй развлкекались. Только некторые, похоже, так и не повзрослели.

T>Поэтому моя вера в reverse engineering тверда и непоколебима.


Важнее то, во что верят люди с толстыми кошельками, которые заказывают музыку. Во что веришь ты — это уже дело десятое.

T>Я жду, когда в Agda2 или в Epigram появится метапрограммирование. Вот там это будет круто просто невероятно, как.


Ну дык прикрути. Какие трудности? Я даже к C++ прикручивал, прикинь. На CINT. Да, я извращенец.

T>Лисп мне неинтересен потому, что на нём сложно сделать суперанализ и


Сложно? Ни фига. Очень даже не сложно. Даже, представь себе, для такого уродливо динамического языка, как Javascript — и то не сложно. Я делал и то, и то.

T> насыщение равенствами.


Хе хе. Я такую технику когда-то независимо изобрёл и в компиляторах применял. Никакой связи с типизацией тут нет. Типы всё равно вырастают в процессе анализа, рано или поздно.

T> Без проверки типов я уже напрограммировался, хватит.


А меня не напрягает. У меня проверка типов есть там, где без неё никак, и нет там, где от неё только лишнее многословие вылезет.

T>Здесь этого не приводилось.


Точно? Ну ладно.

T>Вот, что было:

T>

Надо написать преобразование этого AST, такое, что каждое локально введённое имя будет заменяться на сгенерённый уникальный идентификатор.


Вот мой вариант, куда как более простой и без лишнего синтаксического мусора:
ast lang {
  expr = Const(int:v)
       | Var(ident:nm)
       | App(expr:fn, expr:arg)
       | Let(ident:nm, expr:v, expr:body)
       | Abs(ident:arg, expr:body);}

define testE = #'(Let x (App (Var a) (Var b))
                        (App (App (Var +) (Var x)) (Var y)));

function lexicalrename(expr)
  do loop(e = expr, env = [])
    visit:lang(expr: e) 
    {
       once expr {
          Let -> { nn = gensym();
                   mk:node(nm = nn, v = loop(v,env),
                           body = loop(body, [nm;nn]:env)) }
       |  Abs -> { nn = gensym();
                   mk:node(arg = nn, body = loop(body, [arg;nn]:env)) }
       | deep -> { Var -> { n = lookup(env, nm);
                            if n then mk:node(nm = n) else node }
                   else -> node } }}

writeline(lexicalrename(testE));


T>Для решения выше ты можешь добавить что-то и менять отличные от Let и Var конструкторы.


Ок, согласен — тут всё работает. Даже если добавить:

data E = Const Int
    | Var String
    | App E E
    | Let String E E
    | Abs String E
    | Case E [CE]
    deriving (Typeable,Data,Show)

data CE = CSimple Int [String] E
     deriving (Typeable,Data,Show)


Для тривиальных случаев Typeable срабатывает, хоть и сложновато.

T>А нельзя ли пользоваться сложными преобразованиями,


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

И, кстати, да, твой код с ошибкой — ты Abs забыл. А почему? Потому что многословный он шибко.

T> если есть поддержка системы типов? Если нельзя, то почему?


Потому, что не нужны сложные решения там, где есть простые. Разве это не очевидно? Сложный код должны писать сложные (и дорогостоящие) кодеры. Сложный код дорого поддерживать. В сложном коде проще ошибиться, Abs забыть (да, да, я знаю, что для Case тоже надо отдельно поддержку добавлять).
Re[33]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 21.08.09 11:21
Оценка: 4 (1)
Здравствуйте, VoidEx, Вы писали:

VE>Я не слышал. Гугл сходу не ответил. Не подскажите ссылок, или вкратце, что за свойства?


В книге Чейтина всё выводится.

VE>Тут? Не сохранилось ссылки или хотя бы как искать?


http://lispm.dyndns.org/mov/dsl-in-lisp.mov

Отличный пример, как НЕ НАДО делать DSL-и.
Re[34]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 21.08.09 11:27
Оценка:
Здравствуйте, VoidEx, Вы писали:

VE>Не помешает ли? Я так понимаю, несколько вызовов thlisp запихнут определения в произвольном порядке.


А не по фигу ли? Всё равно определения из текущего модуля использовать нельзя.
Re[33]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 21.08.09 11:38
Оценка:
Здравствуйте, frontsquat, Вы писали:

F>Покажи, как время будет.


Ну, вот, например, list comprehensions:

http://pastebin.com/f48ea86d5
Re[34]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 21.08.09 12:06
Оценка:
Инфиксный синтаксис:

http://pastebin.com/m26a5f2f7
Re[34]: Как написать виртуальную машину на LISP
От: Mirrorer  
Дата: 21.08.09 14:49
Оценка:
А>http://lispm.dyndns.org/mov/dsl-in-lisp.mov

А> Отличный пример, как НЕ НАДО делать DSL-и.


А есть ли где отличный пример как НАДО делать DSL-и ?
Re[34]: Как написать виртуальную машину на LISP
От: thesz Россия http://thesz.livejournal.com
Дата: 21.08.09 15:47
Оценка:
Здравствуйте, Аноним, Вы писали:

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


А>>> Сложно найти такую задачу, которая от метапрограммирования не выигрывала бы. Поскольку метапрограммирование — лучший способ реализации language oriented programming, да да, именно метапрограммирование, а не ФВП.

T>>То-то весь более-менее прогрессивный мир стремится в область зависимых типов...
А> Причём, заметь, началось это всё с лисперов (Axiom).

Ну, я бы не был столь категоричен. Про раннюю историю Axiom практически ничего не известно.

К тому же это computer algebra system, а не ЯП с зависимыми типами.

А> Ты явно ослеплён этими своими типами. Такая примитивная хреновина — а ты их за панацею считаешь.


Я с их помощью уже сейчас уменьшаю количество ошибок.

А>>> Вот про "простое" не поверю. Простое — это прямолинейное. Ты же ищешь сложные обходные пути, лишь бы оно "идиоматично" получилось.


T>>

An idiom is a phrase whose meaning cannot be determined by the literal definition of the phrase itself, but refers instead to a figurative meaning that is known only through common use. (C) Wikipedia


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

А> Ну, такой уж язык, что самое прямолинейное решение в нём оказывается далёким от самого очевидного в терминах предметной области.

В специально выбранной редко встречающейся предметной области.

Решение, причём, человека, не заинтересованного в прямом решении.

T>>Иными словами, наиболее прямое решение.


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


Impedance mismatch.

Наткнулись на выброс essential complexity. Бывает.

Будем знать, что не стоит использовать Хаскель для реализации встроенного Лиспа с компиляцией.

T>>>>А то, что не решает поставленной задачи, так это задача так поставлена, что её хрен решить.

А>>> Что ж ты мне мозги пудришь, про эти ассоциированные типы? Я же сразу сказал, что они не являются ни разу решением этой задачи.
T>>А почему они не являются решением этой задачи? Что мешает их использовать?
А> Потому, блин, что я чётко сказал — меня интересуют чисто статические решения. Причём, решение должно быть чисто функциональным и красимым, всякую херню с плагинами или unsafePerformIO я и так делаю, это мне не нравится.

А если что-то типа unsafePerformIO внесут в синтаксис:
-- было:
-- {-# NOINLINE mainRef #-}
-- mainRef :: IORef String
-- mainRef = unsafePerformIO $ newIORef ""
-- стало:
mainRef :: IORef String
mainRef <- newIORef ""


Будет ли это тогда красимым решением?

T>>Либо ты не хочешь видеть того, что пошатнёт тебя в твоих глазах.

А> Знаешь, в отличии от некоторых, через слово кричащих о своём зашкаливающем IQ, я абсолютно не гордый.
А> Я обычный, нормальный дурак, решающий обычную, нормальную задачу.

Вот она, гордыня-то!

Мне со стороны видится совершенно необычный дурак, выбравший идиотскую задачу, да ещё не смогший её решить.

А> И мне интересно её решение в рамках вполне конкретного подхода. Мне наплевать на другие варианты решения, я их и без тебя знаю. Мне важно найти корректное применение именно 100% статическому метапрограммированию в Хаскелле, а всё остальное не колышет. Так что перестань переводить разговор на нерелевантные темы, пожалуйста. У меня мало времени, и я не хочу его тратить на обсуждение неинтересных мне тем.


На это я пойтить не могу!

T>> Смотри, ты сказал, что reify неприменим по такой-то причине, исправился и продолжил утверждать, что Template Haskell неприменим. Вместо поиска решения с использованием, возможно, других средств Хаскеля.

А> Да не нужны мне другие средства Хаскелля. Мне интересно решить задачу конкретно этим способом. А всякое тупое барахло на комбинаторах я сделать всегда успею.

T>>И продолжал упорствовать, вместо того, чтобы попробовать ассоциированные типы и применить их по месту.


А> Опять ты за своё. Не "по месту" тут динамические решения, абсолютно. В этой задаче они меня не интересуют в принципе.


А>>> Именно, именно. Банальнее некуда.


T>>А семантику пары CREATE..DOES> не расскажешь ли?


А> Дурная у них семантика — CREATE заводит новую запись с словаре, а всё, что между DOES> и ; будет во время компиляции подставлено в каждом приложении определённого CREATE слова. Макра банальнейшая.


Вызвано, не подставлено.

А> Упражнение на вывих мозга — реализовать lexically scoped macros на этом безобразии. Хи хи.


В языке с отсутствием lexical scope? На раз. Любой макрос будет lexically scoped.

А>>> У модели Форта есть очень серьёзные ограничения, делающие метапрограммирование на нём неоправданно сложным.

T>>И какие же?
А> Отсутствие рефлексии by design и сложность её эмуляции.

Слова ' и ['] ?

(оба-на, по-моему, я не ошибся

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


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

T>>Я и другие говорю, что в Форте метапрограммирование есть. Мощное, хорошее метапрограммирование.

А> Ну, мало ли кто неправ. Форт вообще религия какая-то. Сказать фортописцу, что в его разлюбезном Форте кривые макры — лучший способ начала бессмысленного и беспощадного флейма с нулевым конструктивом.

Тут я опять наблюдаю "все не в ногу, один я в ногу".

T>>Ты говоришь, что его там нет.

А> Я говорю, что это слишком примитивно, чтобы быть настоящим метапрограммированием.

Ну, хоть какое-то отступление от генеральной линии.

T>>Я бы согласился с тобой, если бы другие говорили так же, как ты.

А> Большинство лисперов со мной согласятся.

Из тех, что ни разу в жизни не использовали Форт по-фортовски?

T>>Здесь всё та же ситуация, когда ты идёшь в ногу, а все не в ногу.

А> Вся секта идёт не в ногу, ага. А что мне до сектантов? Я из этой палаты выписался давно.

А вот это, как раз, симптом.

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

T>>Намекну. Если инструмент не имеет чётко очерченной области применения, если нельзя придумать способа применения, который приводит к снижению производительности, то этот инструмент имеет божественные качества. Сиречь, является объектом религиозного поклонения, а вдумчивого применения по месту.
А> Ясно. Не знаешь и не понимаешь основ алгоритмической теории информации. Я же намекнул на очень конкретную область применения.

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

Или объясни, как объяснил я.

T>>>>Вызов instance тебе даст упрощение, которое будет проводиться при вызове того, чему присвоили $(thlisp ...).

А>>> Я так и понял, что ты даже не осилил понять того моего примитивного кода. Твоё решение даже так, как ты говоришь, работать не будет.
T>>Почему?
А> Потому, что в рантайме у нас уже просто нет компилятора Лиспа. Совсем. И то, что макра раскроется в рантайме, нам ничем не поможет.

Проведи эксперимент, попробуй.

T>>Измени сигнатуру чего у меня там было в классе с Lisp ty на IO (Lisp ty), и делов. И expand тоже надо будет поменять.

T>>Если это не проходит, то почему?
А> Потому, что после expand структуры LispV проходят через expr2AST, а замет sanitiseAST (а ему нужен полный код выражения, со всеми уже в статике раскрытыми макрами — поскольку в более сложном варианте именно тут должны делаться оптимизации и проводиться проверки корректности). Результат этого безобразия подаётся compile_expr :: LispAst -> Q Exp; Прошу внимательнее посмотреть на эту сигнатуру. Тут просто нет места уже никаким LispV, за исключением константных списков.
А> Надо ли говорить, что в рантайме у нас compile_expr работать не будет вообще? И это кстати правильно и я это полностью поддерживаю, это в рамках идеологии TH.

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

Оптимизация, так сказать.

T>>Заведи IORef с макросами.

А> Блин. И эти люди запрещают мне ковыряться в носу?!? Я раз двадцать всего лишь сказал, что мне нужно православное решение. Что-то типа runMeta внутри монады Q.

Получается, что тебе нужно не решение на современном Хаскеле, а решение ровно такое, какое ты считаешь правильным.

Вместе с "преждевременной оптимизацией" выше это звучит приговором тебе, как программисту.

А> Чисто функциональненько, без всяких там императивных грязных хаков. С хаками я и так сделал, это не интересно. Я то предлагаю тривиальную модификацию TH, которая позволит такие вещи делать чистым и безопасным способом, блин.


Лично я не вижу в этом потребности.

T>>topDecls = unsafePerformIO $ newIORef []

А> Нда... И после этого кое кто боится, что рефлексия может оказаться малость нетипобезопасной. Кто не параноик, я не параноик?!?

Это высказывания я вообще не понял.

T>>В энтот IORef можно запендюривать всё, что душе угодно.

А> Угу. А толку то? Это неправославно.

— Мадемуазель, вы дура!
— Это означает, мадам, что моё мнение не совпадает с вашим.

(С) Рафаэль Сабатини

T>>Например, код макросов супротив их имени.

А> Так и делаю. Но это очень некрасиво.

Нет ничего некрасивого в этом.

T>>По-моему, я круче и поэтому метапрограммирование — отстой.

А> Да нет, не круче. Ты Лиспа не знаешь. Как может быть крутым кто-то, кто не знает кошегъного пгавославного Лиспа?

Все основные фичи Лиспа знают все нормальные функциональные программисты. Я не знаю тонкостей и подробностей, как и остальные нормальные функциональные программисты.

T>>Хотя с идеей насчёт IORef, что выше, проблем уже не должно возникнуть.

А> Ну и где тут православность?

В глазах наблюдателя.

А>>> А вот теперь уже моя очередь умывать руки... Даже не представляю, что на такую чушь можно возразить.

T>>Если это не так, то приведи опровергающий пример.
А> Посчитай мне параллельно ряд Фибоначчи. Вообще любая задача, в которой следующая итерация зависит от результата предыдущей, параллелизации не поддаётся принципиально.

С Фибоначчи я согласен, но я не вижу причин, по которым метапрограммирование существенно ускорит эту задачу.

T>>BTW, я занимался проектированием параллельных железок (процесоров) и созданием алгоритмов автоматического распараллеливания для них. Я знаю, о чём говорю.

А> Да хорош уже понтоваться, это надоедать начинает. Я вон тоже когда-то давно на Occam-е писал под инмосы. И кластеры строил, для числомолотильни на MPI. И агентным моделированием занимался. Уж что можно распараллелить, а что не получится даже в самой смелой теории, я прекрасно знаю.

Но ты не знаешь подробностей.

Вот, например, возможно ли параллельно выполнить сортировку пузырьком:
for (i = N; i>=1;i--) {
    for (j=0;i<i-1;j++) {
        if (a[j] > a[j+1]) {
            int t = a[j];
            a[j] = a[j+1];
            a[j+1] = t;
        }
    }
}


T>>Приведи ссылку. В английской википедии толкование расширительное, пересекается с компиляцией.

А> Угу, угу. Я ж говорю — это самый общий случай. Любой процесс, результатом которого является код любого уровня, является метапрограммированием.

Тогда стоит завязать с упоминанием "метапрограммирования" и пользоваться терминами, обозначающими отдельные его варианты.

Потому, что в метапрограммирование ты заносишь только то, что приносит радость, а грусть тщательно убираешь.

T>>Решая повседневные задачи, мне не приходится изощряться ни как на Лиспе, ни как-нибудь ещё. Я их просто решаю.

А> На Лиспе как раз изощряться не приходится. А вот городить всякие там типы, классы, шмассы, да ещё и там, где таких терминов то в предметной области нет и не предвидится — это и есть "изощряться".

Что там насчёт Curry-Howard isomorphism?

T>>Так проще.

А> Нет, не проще.

Приведи данные о себе, чтобы я смог сравнить.

T>>А если что, то rewrite rules, да ассоциированные типы.

А> Не проще. Свой механизм term rewriting и своя система типов всегда будет проще и более подойдёт под задачу, чем частный и ограниченный механизм Хаскелля.

Не рекомендую.

T>>Что сейчас скажешь?

А> Что православного решения нет, и что механизм не работает. Что мешает тогда пуститься во все тяжкие, и даже newName реализовать через runIO? И монаду Quasi вообще выкинуть за ненадобностью. А, стрёмно, да? Ну так вот и контекст так тащить — тоже стрёмно.

Почему стрёмно?

А>>> Даже среди лисперов очень мало тех, кто умеет пользоваться метапрограммированием. Большинство делают одну и ту же ошибку — чрезмерно сложное преобразование в один проход. Почти никто не понимает истинного подхода — инкрементального метапрограммирования, с тривиальными преобразованиями на каждом этапе.

T>>Это точно религия, прошу прощения за мой французский.
А> Нет, это метод. Который работает. Всегда и надёжно. В отличие от.

Если "всегда и надёжно", то это религия, не метод.

Методы работают "от сих и до сих, а в остальных местах не работают"

А>>> Показать, например, реализацию pattern matching в Лиспе, сделанную таким способом? Или, например, list comprehensions? Или реализацию инфиксного синтаксиса?

T>>Синтаксисом меня не напугать.
А> Не отмазывайся. Если бы в Хаскелле не было list comprehensions — как бы ты их делал? Подозреваю, что очень криво и сложно.

>>=


A> А на Лиспе решение тривиально.

А> Кстати, list comprehensions это таки не "синтакис", это вполне себе семантика.

Которую можно описать rewrite rules.

T>>Покажи, лучше, GADT, type classes, да type families с выводом типов.

А> Простейший вариант Хиндли-Милнера я уже показывал.

Где?

А> Любые расширения делаются точно так же, тем более что всё это делается на основе Пролога, и тут варианты развития системы типов просто безграничны.


HSM(X) это CLP(X). Не Пролог, как многие ошибочно предполагают, а программирование в ограничениях.

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


Я бы хотел увидеть реализацию.

T>>>>Ты, вон, приведи код функции, что не даёт подать на свой вход код с нераскрытыми макросами.

А>>> Это вообще как? Макросы раскрываются компилятором, какой такой вообще "код" может быть подан на вход функции в рантайме?
T>>Ну, хорошо.
T>>Покажи функцию, что не даёт подать на вход AST с сохранившимися let и where конструкциями.
А> Так это другой уже AST будет. С другим типов. Кто ж позволит то, если сигнатура функции, например, AstAfterExpansion -> AstLifted, применить её к RawAst?

Анализы могут быть одинаковые.

Тип анализа AST x -> Result, туда можно подать AST (LET ::: WHERE) и AST ().

T>>Последнее где-то в блогах обнаружил.

А> Ссылку, ссылку pls. Мне реально интересно.

Не могу найти, увы. Я бы и рад поделиться, но не могу. Здесь безо всякой издёвки.

T>>Но действительно, контекст IO типа позволяет делать ввод-вывод и обычные вычисления, отсутствие этого контекста — только обычные вычисления. Сами обычные вычисления можно структурировать дальше: разборщики, преобразователи, работающие со списками и тп.

А> Да никто не спорит, что типы — офигенно мощный инструмент структурирования кода. Я говрю, что это не единственный инструмент, и не самый общий.

Per Martin-Lof would disagree with you.

А>>> Да ну? Я это условие сформулировал в самом начале ещё, читай внимательнее. Я отвечал на вопрос, почему нельзя код динамически генерить, и сказал, что это минимально приемлемая защита от reverse engineering.


T>> Я как-то вскрыл пароль, повешенный на программу, написанную на симуляторе процессора с одной командой.


А> Представь себе — пятьдесят мегабайт скриптового кода (ну, например, всякая сложная логика для CAD — лестницы там строить, трубы прокладывать, и т.п., и всё это — очень-очень дорогостоящая собственность какой либо инженерной конторы при какой либо, например, Shell). В одном случае ты их просто выдираешь в голом виде и тащиш к конкурентам, в другом случае ищешь Сергея Зефирова, который вскрывает логику каждой отдельной функции за сутки. Берёт за свою работу, ну, допустим, $1500 в сутки, и работает над этим делом, ну, эдак, лет много — каждая функция килобайт по 2-5, а кода у нас пятьдесят мегабайт без комментариев. В этом варианте злой конкурент только плюнет на всё, и пойдёт сам логику сочинять, или стухнет, и заказчик его пойдёт к той инженерной конторе, которая этой логикой владеет.


Я написал специальный отладчик, что восстанавливал код в высокоуровневых конструкциях.

То же сделает и Сергей Зефиров за $1500 в сутки.

T>>Поэтому моя вера в reverse engineering тверда и непоколебима.

А> Важнее то, во что верят люди с толстыми кошельками, которые заказывают музыку. Во что веришь ты — это уже дело десятое.

Иными словами, ты обманщик.

T>>Я жду, когда в Agda2 или в Epigram появится метапрограммирование. Вот там это будет круто просто невероятно, как.

А> Ну дык прикрути. Какие трудности? Я даже к C++ прикручивал, прикинь. На CINT. Да, я извращенец.

Этим должны заниматься люди поумней меня.

T>>Лисп мне неинтересен потому, что на нём сложно сделать суперанализ и

А> Сложно? Ни фига. Очень даже не сложно. Даже, представь себе, для такого уродливо динамического языка, как Javascript — и то не сложно. Я делал и то, и то.

Для нормально работающего суперанализа требуется параметризация типов.

T>> насыщение равенствами.

А> Хе хе. Я такую технику когда-то независимо изобрёл и в компиляторах применял. Никакой связи с типизацией тут нет. Типы всё равно вырастают в процессе анализа, рано или поздно.

Типы снижают количество ошибок.

T>> Без проверки типов я уже напрограммировался, хватит.

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

Параграфом выше ты отказывал в проверке типов там, где она необходима — в преобразованиях компиляторов.

Я тебе не верю.

T>>Вот, что было:

T>>

Надо написать преобразование этого AST, такое, что каждое локально введённое имя будет заменяться на сгенерённый уникальный идентификатор.


А> Вот мой вариант, куда как более простой и без лишнего синтаксического мусора:


У меня есть окружения для gensym, у тебя нет, весь diff. По общей сложности разница минимальна, если вообще есть.

А>
А>ast lang {
А>  expr = Const(int:v)
А>       | Var(ident:nm)
А>       | App(expr:fn, expr:arg)
А>       | Let(ident:nm, expr:v, expr:body)
А>       | Abs(ident:arg, expr:body);}

А>define testE = #'(Let x (App (Var a) (Var b))
А>                        (App (App (Var +) (Var x)) (Var y)));

А>function lexicalrename(expr)
А>  do loop(e = expr, env = [])
А>    visit:lang(expr: e) 
А>    {
А>       once expr {
А>          Let -> { nn = gensym();
А>                   mk:node(nm = nn, v = loop(v,env),
А>                           body = loop(body, [nm;nn]:env)) }
А>       |  Abs -> { nn = gensym();
А>                   mk:node(arg = nn, body = loop(body, [arg;nn]:env)) }
А>       | deep -> { Var -> { n = lookup(env, nm);
А>                            if n then mk:node(nm = n) else node }
А>                   else -> node } }}

А>writeline(lexicalrename(testE));
А>


T>>Для решения выше ты можешь добавить что-то и менять отличные от Let и Var конструкторы.


А> Ок, согласен — тут всё работает. Даже если добавить:


А>
А>data E = Const Int
А>    | Var String
А>    | App E E
А>    | Let String E E
А>    | Abs String E
А>    | Case E [CE]
А>    deriving (Typeable,Data,Show)

А>data CE = CSimple Int [String] E
А>     deriving (Typeable,Data,Show)
А>


А> Для тривиальных случаев Typeable срабатывает, хоть и сложновато.


T>>А нельзя ли пользоваться сложными преобразованиями,

А> Нельзя. Их сложно понимать, сложно поддерживать. Вот представь, этот твой код для переименования переменных кто-то другой править будет.
А> И, кстати, да, твой код с ошибкой — ты Abs забыл. А почему? Потому что многословный он шибко.

Не забыл. В техзадании было про let, abs я ввёл для красоты.

T>> если есть поддержка системы типов? Если нельзя, то почему?

А> Потому, что не нужны сложные решения там, где есть простые. Разве это не очевидно? Сложный код должны писать сложные (и дорогостоящие) кодеры. Сложный код дорого поддерживать. В сложном коде проще ошибиться, Abs забыть (да, да, я знаю, что для Case тоже надо отдельно поддержку добавлять).

Типы не дадут. Как не дадут разобрать AST с присутствующим WHERE при генерации отдельных определений суперкомбинаторов.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[35]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 21.08.09 17:01
Оценка:
Здравствуйте, thesz, Вы писали:

T>К тому же это computer algebra system, а не ЯП с зависимыми типами.


А Coq вообще proof assistant. Но тоже ведь флагманский блин язык с зависимыми блин типами. Тем более что A# используют и в отрыве от остальной Axiom.

А>> Ты явно ослеплён этими своими типами. Такая примитивная хреновина — а ты их за панацею считаешь.


T>Я с их помощью уже сейчас уменьшаю количество ошибок.


А, крокодильчиков отгоняешь. Ясненько.

А>> Ну, такой уж язык, что самое прямолинейное решение в нём оказывается далёким от самого очевидного в терминах предметной области.


T>В специально выбранной редко встречающейся предметной области.


В любой, абсолютно в любой. Я что-то не знаком с предметными областями, где среди терминологии были бы всякие "data", "instance", а то и вовсе "mapM". Если что-то такое попадается в решении, относящемся к задаче из этой предметной области — значит язык мешает. Примешивает свои нерелевантные концепции. Чего быть в идеальном случае не должно.

T>Impedance mismatch.


T>Наткнулись на выброс essential complexity. Бывает.


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

T>Будем знать, что не стоит использовать Хаскель для реализации встроенного Лиспа с компиляцией.


Его вообще много для чего не стоит использовать. Что нисколько не умаляет его достоинств в тех задачах, где его использовать стоит.

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

T>А если что-то типа unsafePerformIO внесут в синтаксис:


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


T>Мне со стороны видится совершенно необычный дурак, выбравший идиотскую задачу, да ещё не смогший её решить.


Ну, во первых, не тебе судить об идиотизме задачи, о которй ты ни хрена не знаешь.Во вторых, задача — она на то и задача, что или она решается, или нет — и последнее говорит о наличии принципиальных ограничений инструмента. И дальнейшее обсуждение уже должно идти о том, оправданы ли эти ограничения, или нет. И лично с тобой мне это обсуждать совершенно не интересно. Человек, который считает unsafePerformIO допустимым, но слышать ничего не желает о вложенных сплайсах, например — как минимум чего-то очень сильно не догоняет. И вряд ли что-то ценное сможет внести в религиозный спор о семантике раскрытия сплайсов.

T>На это я пойтить не могу!


Я ж говорил, что твоя цель — пофлеймить. То есть, прямая противоположность моей цели, сугубо практической.

А>> Дурная у них семантика — CREATE заводит новую запись с словаре, а всё, что между DOES> и ; будет во время компиляции подставлено в каждом приложении определённого CREATE слова. Макра банальнейшая.


T>Вызвано, не подставлено.


Подставлено и исполнено в режиме интерпретации.

А>> Упражнение на вывих мозга — реализовать lexically scoped macros на этом безобразии. Хи хи.


T>В языке с отсутствием lexical scope? На раз. Любой макрос будет lexically scoped.


Я же говорю — ну ни хрена ты не понимаешь в метапрограммировании. Просто абсолютно ни хрена не понимаешь.

Метаязык на то и метаязык, что проблема отсутствия lexical scope в нём должна легко разрешаться — просто модификацией самого языка, средствами этого самого языка. Как раз потому игрушечная задача "сделать на метаязыке лисп с макрами" и является тем аналогом теста на Тьюринг-полноту (реализовать лямбда-вычислитель, машину Тьюринга, или что ещё), но для оценки полноценности метапрограммирования.

А>> Отсутствие рефлексии by design и сложность её эмуляции.


T>Слова ' и ['] ?


Нет, ты как всегда мимо тазика. Это тебе явно свойственно.

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


T>Опять же, если работать в привычном тебе ключе. И решать задачи именно привычным тебе способом.


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

А>> Большинство лисперов со мной согласятся.


T>Из тех, что ни разу в жизни не использовали Форт по-фортовски?


Я так подозреваю, очень мало в природе найдётся Лисперов, которые в юности не написали как минимум одну реализацию своего Форта. Я уж не говорю про реализации Лиспа.

А>> Вся секта идёт не в ногу, ага. А что мне до сектантов? Я из этой палаты выписался давно.


T>А вот это, как раз, симптом.


Сам то, сам то — явно в ту палату не вхож. Там лечатся махровые динамщики. Человеку, настолько фанатично верующему в статическую типизацию, туда хода нет.

А>> Ясно. Не знаешь и не понимаешь основ алгоритмической теории информации. Я же намекнул на очень конкретную область применения.


T>Приведи ссылку, чего намекать.


Что-то ты смайликов много лепишь. От неуверенности, да?

T>Или объясни, как объяснил я.


Нет уж, продолжу намекать — поскольку это уж совсем уход в сторону от нужной мне темы, стараться и напрягаться я тут не намерен. При определении сложности (по Колмогорову) метапрограммирование (понимаемое как трансляция из одного языка в другой, причём, в силу особенностей определения, именно встраиваемая трансляция — хотя, решение на ФВП тут тоже будет считаться метапрограммированием) получается единственным способом устранения шума.

А>> Потому, что в рантайме у нас уже просто нет компилятора Лиспа. Совсем. И то, что макра раскроется в рантайме, нам ничем не поможет.


T>Проведи эксперимент, попробуй.


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

А>> Надо ли говорить, что в рантайме у нас compile_expr работать не будет вообще? И это кстати правильно и я это полностью поддерживаю, это в рамках идеологии TH.


T> Итак, тебе нужна компиляция и оптимизация самого GHC.


Да, конечно же. Более того, мне нужна компиляция, оптимизация, проверки типов, и т.п., при чём не только от самого хост-языка, но и от всех языков, надстроенных над ним. То есть, например, мне нужна в том числе и возможность транслировать код некоего DSL в этот самый Лисп, который, в свою очередь, будет уже транслироваться в Хаскелль. Именно это и есть метапрограммирование — итеративное надстраивание новых свойств над одним базовым языком.

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


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

Ты видел Helium, и его VM? Как раз на таких идеях построено, на последовательности как можно более тупых и доказуемых преобразований. Я из этой VM много умных и полезных идей наворовал...

T>Оптимизация, так сказать.


Я же говорю, что ни фига ты не понимаешь в метапрограммировании.

T>>>Заведи IORef с макросами.

А>> Блин. И эти люди запрещают мне ковыряться в носу?!? Я раз двадцать всего лишь сказал, что мне нужно православное решение. Что-то типа runMeta внутри монады Q.

T>Получается, что тебе нужно не решение на современном Хаскеле, а решение ровно такое, какое ты считаешь правильным.


Опачки. Теперь уже императивное решение с runIO — это "решение на современном Хаскеле", а чисто функциональное и безопасное решение, которое предлагаю я — идеологическая диверсия? Да ты совсем зарапортовался. Не к лицу евангелисту Хаскеля петь диферамбы позорному IORef!

T>Вместе с "преждевременной оптимизацией" выше это звучит приговором тебе, как программисту.


Боюсь, не тебе решать. Увы.

А>> Чисто функциональненько, без всяких там императивных грязных хаков. С хаками я и так сделал, это не интересно. Я то предлагаю тривиальную модификацию TH, которая позволит такие вещи делать чистым и безопасным способом, блин.


T>Лично я не вижу в этом потребности.


Ну это ты. Ты вообще много чего не видишь — классы типов взор застилают.

T>>>topDecls = unsafePerformIO $ newIORef []

А>> Нда... И после этого кое кто боится, что рефлексия может оказаться малость нетипобезопасной. Кто не параноик, я не параноик?!?

T>Это высказывания я вообще не понял.


Ну, что я могу сказать — поздравляю.

T>>>Например, код макросов супротив их имени.

А>> Так и делаю. Но это очень некрасиво.

T>Нет ничего некрасивого в этом.


Ок, ок. Ничего некрасивого нет. Тогда давай вообще монаду Q выкинем. На фига она? Будем императивно и в произвольном неопределённом порядке дёргать за небезопасный код.

T>>>По-моему, я круче и поэтому метапрограммирование — отстой.

А>> Да нет, не круче. Ты Лиспа не знаешь. Как может быть крутым кто-то, кто не знает кошегъного пгавославного Лиспа?

T>Все основные фичи Лиспа знают все нормальные функциональные программисты.


Основная фича Лиспа — это defmacro. Все другие никакого интереса не представляют. И вот как раз её ты и не понимаешь.

T> Я не знаю тонкостей и подробностей, как и остальные нормальные функциональные программисты.


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

T>В глазах наблюдателя.


Странная у тебя религия. unsafePerformIO можно, а eval нельзя. Не понимаю!

А>> Посчитай мне параллельно ряд Фибоначчи. Вообще любая задача, в которой следующая итерация зависит от результата предыдущей, параллелизации не поддаётся принципиально.


T>С Фибоначчи я согласен, но я не вижу причин, по которым метапрограммирование существенно ускорит эту задачу.


Не видишь? Думаю, что низкоуровневый код, сгенерённый в рантайме с помощью Harpy (тоже метапрограммирование получается), будет работать быстрее чем то, что сделает ghc, при всех его оптимизациях. Одна из фичей метапрограммирования — возможность выбора семантики целевого языка. Если нужно что-то тупое и низкоуровневое — пожалуйста. Нужен Хаскелль со всеми своими прелестями — легко. И Пролог, и Occam — всё что угодно, всё, что наиболее задаче подходит, и всё — в одном флаконе.

T>Но ты не знаешь подробностей.


Мне достаточно знания теоретических ограничений.

T>Вот, например, возможно ли параллельно выполнить сортировку пузырьком:


Тогда odd-even sort получится. В принципе умный компилятор может её вывести автоматически из такого определения сортировки пузырьком.

T>Тогда стоит завязать с упоминанием "метапрограммирования" и пользоваться терминами, обозначающими отдельные его варианты.


С чего вдруг? Формально я прав, и не колышет. Любая кодогенерация есть метапрограммирование. И я, когда говорю о метапрограммировании, имею в виду любой вариант кодогенерации. Когда кодогенерация имеет место быть во время компиляции, я говорю о статическом метапрограммировании (твои типичные решения — это динамическое метапрограммирование). Когда я говорю о комбинируемых цепочках преобразований кода — это инкрементальное метапрограммирование.

T>Потому, что в метапрограммирование ты заносишь только то, что приносит радость, а грусть тщательно убираешь.


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

T>>>Решая повседневные задачи, мне не приходится изощряться ни как на Лиспе, ни как-нибудь ещё. Я их просто решаю.

А>> На Лиспе как раз изощряться не приходится. А вот городить всякие там типы, классы, шмассы, да ещё и там, где таких терминов то в предметной области нет и не предвидится — это и есть "изощряться".

T>Что там насчёт Curry-Howard isomorphism?


Что насчёт изоморфизма Карри-Говарда? Что там насчёт лямбда-куба? О чём сказать то хотел?

T>>>А если что, то rewrite rules, да ассоциированные типы.

А>> Не проще. Свой механизм term rewriting и своя система типов всегда будет проще и более подойдёт под задачу, чем частный и ограниченный механизм Хаскелля.

T>Не рекомендую.


Рекомендаций не принимаю. Источник недостаточно авторитетен.

А>> Что православного решения нет, и что механизм не работает. Что мешает тогда пуститься во все тяжкие, и даже newName реализовать через runIO? И монаду Quasi вообще выкинуть за ненадобностью. А, стрёмно, да? Ну так вот и контекст так тащить — тоже стрёмно.


T>Почему стрёмно?


А почему ты вообще тогда на Хаскелле пишешь. Возьми императивный язык OCaml, и радуйся жизни.

А я вот сайд-эффектов хотел бы избегать. Точнее, я использую Хаскелль там, где у меня есть резон избегать сайд-эффектов. И ты мне тут предлагаешь сделать из Хаскелля очередной грязный императивный язык. Я удивлён.

А>> Нет, это метод. Который работает. Всегда и надёжно. В отличие от.


T>Если "всегда и надёжно", то это религия, не метод.


Нет, это всего лишь теория. Наиболее общий метод работает более всегда, чем отдельные его частные случаи.

А>> Не отмазывайся. Если бы в Хаскелле не было list comprehensions — как бы ты их делал? Подозреваю, что очень криво и сложно.


> >>=


Код показывай. Я то представляю, как это будет выглядеть. Кривенько это будет выглядеть.

A>> А на Лиспе решение тривиально.

А>> Кстати, list comprehensions это таки не "синтакис", это вполне себе семантика.

T>Которую можно описать rewrite rules.


Которые, в свою очередь, равномощны макрам в Схеме. Смотри, допрыгаешься — расхваливаешь тут статическое метапрограммирование, собратья по динамической комбинаторной секте тебя заклюют насмерть.

T>>>Покажи, лучше, GADT, type classes, да type families с выводом типов.

А>> Простейший вариант Хиндли-Милнера я уже показывал.

T>Где?


Была ссылка на реализацию встроенного в Лисп ML. Была ссылка на вывод типов от lispnik-а. И ещё вроде что-то пробегало уже в этой ветке аналогичное.

T>HSM(X) это CLP(X). Не Пролог, как многие ошибочно предполагают, а программирование в ограничениях.


Любой приличный пролог давно уже содержит расширения для constraint programming.

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


T>Я бы хотел увидеть реализацию.


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

T>Анализы могут быть одинаковые.


T>Тип анализа AST x -> Result, туда можно подать AST (LET ::: WHERE) и AST ().


На фига такие сложности? Прекрасный способ ошибиться.

T>Не могу найти, увы. Я бы и рад поделиться, но не могу. Здесь безо всякой издёвки.


Попробую Луку Карделли поспрашивать, что он сам про это думает. Или Милнера...

T>Я написал специальный отладчик, что восстанавливал код в высокоуровневых конструкциях.


Хе хе. Компилятор, допускающий однозначную и применимую на практике декомпиляцию — это epic fail.

T>>>Поэтому моя вера в reverse engineering тверда и непоколебима.

А>> Важнее то, во что верят люди с толстыми кошельками, которые заказывают музыку. Во что веришь ты — это уже дело десятое.

T>Иными словами, ты обманщик.


Нет, почему же? Я никогда не утверждаю, что вскрытие невозможно. Я говорю о стоимости такого вскрытия.

T>>>Я жду, когда в Agda2 или в Epigram появится метапрограммирование. Вот там это будет круто просто невероятно, как.

А>> Ну дык прикрути. Какие трудности? Я даже к C++ прикручивал, прикинь. На CINT. Да, я извращенец.

T>Этим должны заниматься люди поумней меня.


Да что ты говоришь? Неужели такие существуют в природе?

А>> Сложно? Ни фига. Очень даже не сложно. Даже, представь себе, для такого уродливо динамического языка, как Javascript — и то не сложно. Я делал и то, и то.


T>Для нормально работающего суперанализа требуется параметризация типов.


Совершенно не обязательно. При специализации (частичном приложении) параметризованные типы и так выводятся. Снаружи сугубо динамический язык, а внутри — статически типизированный получается. Красота.

T>Типы снижают количество ошибок.


Это мантра такая? Типа хари кришны?

Они не только снижают количество ошибок. Они ещё и под ногами путаться умеют. И надо уметь находить разумный баланс.

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


T>Параграфом выше ты отказывал в проверке типов там, где она необходима — в преобразованиях компиляторов.


Как это отказывал? Я говорил об автоматическом выводе типов для динамических языков. Ссылочек на интересные работы по этой теме подкинуть, или ты и так LtU почитываешь?

А>> Вот мой вариант, куда как более простой и без лишнего синтаксического мусора:


T>У меня есть окружения для gensym, у тебя нет, весь diff.


Не только. У тебя ещё много всякого семантического мусора, который ничего не говорит о собственно рассказываемой сказке. В сказке про переименование переменных нет никаких слов про liftM, fst, snd, и т.п. Это слова из совсем другой сказки. Это — типичный случай leaky abstraction.

T> По общей сложности разница минимальна, если вообще есть.


Только вот реализация компилятора Лиспа для моего варианта ещё и на порядки проще. То есть, метапрограммированием сделано то же, что классическим способом, сам признаёшь минимальность разницы, но сделано на порядки дешевле. И так с любой языковой фичёй, какую только сможешь упомнить. ast:visit гораздо проще, чем реализация Typeable, и не требует плясок с внутренностями компилятора. У тебя же на любой чих надо "придумать новый синтаксис", добавить что-то в desugaring. Зачем? Можно проще и дешевле.

И я пока ещё был добрый и не предлагал садистских вариантов. Таких, как добавление в каждый конструктор по ссылке на Location, или преобразование всего типа E везде в тип (Tag * E) (например, для дальнейшего вывода типов, или системы уравнений для доказательства каких либо свойств относительно этого кода). Я уж не говорю об инкрементальных изменениях AST, которые выльются в многословные изменения связанного с ними кода.

А>> И, кстати, да, твой код с ошибкой — ты Abs забыл. А почему? Потому что многословный он шибко.


T>Не забыл. В техзадании было про let, abs я ввёл для красоты.


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

T>Типы не дадут.


Вот это уже точно религия. Как это типы не дадут ошибиться в сложной логике преобразования? Проще она от типов не станет. Корректный тип ещё не значит корректности выполнения.

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

T> Как не дадут разобрать AST с присутствующим WHERE при генерации отдельных определений суперкомбинаторов.


Это мелочи. От серьёзных ошибок типы не защитят, и они не помогут в понимании логики преобразования.
Re[36]: Как написать виртуальную машину на LISP
От: thesz Россия http://thesz.livejournal.com
Дата: 21.08.09 20:04
Оценка:
T>>Наткнулись на выброс essential complexity. Бывает.
А> А это при твоих забавных подходах к программированию бывает сплошь и рядом. Про парадигму, в рамках которой impedance mismatch обходится, ты и слышать не желаешь, поскольку религиозен чрезмерно.

Есть такой журнал, Практика Функционального Программирования называется, http://fprog.ru

Если тебе есть, что сказать, говори там.

Здесь ты мне надоел.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[34]: Как написать виртуальную машину на LISP
От: VoidEx  
Дата: 21.08.09 22:08
Оценка:
Здравствуйте, Аноним, Вы писали:

VE>>Тут? Не сохранилось ссылки или хотя бы как искать?


А>http://lispm.dyndns.org/mov/dsl-in-lisp.mov


А> Отличный пример, как НЕ НАДО делать DSL-и.


Спасибо. Присоединюсь к просьбе Mirrorer'а, нет ли примеров правильного построения DSL'ей?
Re[35]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 25.08.09 09:51
Оценка: 20 (2) +1
Здравствуйте, VoidEx, Вы писали:

VE>Спасибо. Присоединюсь к просьбе Mirrorer'а, нет ли примеров правильного построения DSL'ей?


Про лисповский подход:

P. Seibel, "Practical Common Lisp".

Кошернейший пример на Haskell:

http://www.lexifi.com/downloads/frankau.pdf
Re[34]: Как написать виртуальную машину на LISP
От: Mirrorer  
Дата: 26.08.09 08:04
Оценка:
Здравствуйте, Аноним, Вы писали:

А> В книге Чейтина всё выводится.


Одолел где-то треть книжки Чейтина. Возник вопрос.
Ну допуспустим, мы скомпилили код из 4х строчек для регистровой машины в диофантово уравнение в 20К символов.
И это уравнение разрешимо только в том случае, если программа не подвисает. Как бы заменили проблему останова проблемой проверки разрешимости диофантова уравнения. Но диофантовы уравнения ведь в общем виде алгоритмически неразрешимы ? Смысл такого телодвижения ? Заменить одну неразрешимую задачу другой? Или дальше по книге будут доказываться интересные свойства программ основанные на анализе этих самых уравнений ?
Re[35]: Как написать виртуальную машину на LISP
От: FR  
Дата: 26.08.09 09:58
Оценка:
Здравствуйте, Mirrorer, Вы писали:

M>Одолел где-то треть книжки Чейтина. Возник вопрос.


Можно ссылочку на книгу.
Re[36]: Как написать виртуальную машину на LISP
От: Курилка Россия http://kirya.narod.ru/
Дата: 26.08.09 10:03
Оценка: 10 (1) +1
Здравствуйте, FR, Вы писали:

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


M>>Одолел где-то треть книжки Чейтина. Возник вопрос.


FR>Можно ссылочку на книгу.


Насколько понимаю вот.
Re[37]: Как написать виртуальную машину на LISP
От: Mirrorer  
Дата: 26.08.09 11:21
Оценка: 10 (1) +1
Здравствуйте, Курилка, Вы писали:

К>Насколько понимаю вот.


Книжечка та, но есть более прямые ссылки
Например отсюда в разделе библиография.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.