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...
Пока на собственное сообщение не было ответов, его можно удалить.