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>Всё замечательно работает.


В таком варианте — вообще никак не работает.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.