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

L>>Всё замечательно работает.

А> В таком варианте — вообще никак не работает.

Так! Давай я expand macro писать не буду, а напишу декоративный пример, и ты мне покажешь, где именно проблема, ок?

Тут у нас файл Macro.hs, в котором определён макрос list (это не он, но нам важен же вызов при компиляции, а не что он делает, так?)

module Macro where

import Language.Haskell.TH

$( [d| list = id |] ) -- как будто мы его сгенерировали с помощью thlisptop


А вот файл Main.hs, который использует list во время компиляции (т.е. рантайм list зваться не будет)

import Macro
import Language.Haskell.TH

o_O = 42

main = print $( [| $(varE (mkName "list")) o_O |] )


Т.е. $(varE (mkName "list")) даёт нам list, [| |] даёт нам выражение list o_O, а внешний $() вызывает его компайл-тайм.

Чего я не вижу?
Re[33]: Как написать виртуальную машину на LISP
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 19.08.09 12:23
Оценка:
Здравствуйте, lomeo, Вы писали:

L>Т.е. $(varE (mkName "list")) даёт нам list, [| |] даёт нам выражение list o_O, а внешний $() вызывает его компайл-тайм.


Я гоню, пора в отпуск
Re[33]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 19.08.09 12:26
Оценка:
Здравствуйте, lomeo, Вы писали:

L>
main = print $( [| $(varE (mkName "list")) o_O |] )


L>Т.е. $(varE (mkName "list")) даёт нам list, [| |] даёт нам выражение list o_O, а внешний $() вызывает его компайл-тайм.


Не вызовет он никакой list во время компиляции. Он его тупо подставит.

L>Чего я не вижу?


Того, что это выражение будет скомпилировано в код:
main = print (list o_O)
Re[34]: Как написать виртуальную машину на LISP
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 19.08.09 13:10
Оценка:
Здравствуйте, Аноним, Вы писали:

А> Того, что это выражение будет скомпилировано в код:

А>
А>main = print (list o_O)
А>


Я понял — проблема — в получении функции по имени и тут же по месту её вызова. Может быть стоит попробовать решение а-ля hs-plugins?
Или при создании макроса регистрировать её в некой глобальной переменной по имени и тогда можно будет просто получить её?
Re[35]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 19.08.09 13:44
Оценка:
Здравствуйте, lomeo, Вы писали:

L>Я понял — проблема — в получении функции по имени и тут же по месту её вызова.


Да, именно так.

L> Может быть стоит попробовать решение а-ля hs-plugins?


Это хак будет.

L>Или при создании макроса регистрировать её в некой глобальной переменной по имени и тогда можно будет просто получить её?


Конечно же так можно — но это уже совершенно неправославно, о чём я тут, собственно, и сокрушаюсь. Просто я недоумеваю — reify есть и считается православным, runMeta внутри есть, и реализовано вполне православно — что ж его не дать простому смертному пользователю подёргать точно так же, как reify?
Re[36]: Как написать виртуальную машину на LISP
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 19.08.09 14:05
Оценка:
Здравствуйте, Аноним, Вы писали:

А> Конечно же так можно — но это уже совершенно неправославно, о чём я тут, собственно, и сокрушаюсь. Просто я недоумеваю — reify есть и считается православным, runMeta внутри есть, и реализовано вполне православно — что ж его не дать простому смертному пользователю подёргать точно так же, как reify?


Угу, обидно. В лиспе программы, которые пишут программы, которые пишут программы...
А в Хаскель только программы, которые пишут программы.

В общем я почитал, уровень можно поднять только из другого модуля (нет вложенных сплайсов), т.е. кошерного способа сделать это через TH нет.
Re[30]: Как написать виртуальную машину на LISP
От: awson  
Дата: 19.08.09 22:12
Оценка: 1 (1)
Здравствуйте, Аноним, Вы писали:

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


Не нужно фантазировать. Хотя кое-что изменилось со времен написания основного документа — принципы остались на месте. В частности, оттуда можно почерпнуть знание о том, что существенная часть ограничений (включающая все, которые вы ищете способ преодолеть) образовалась не по недоразумению, а вполне себе by design. Эта мысль проходит буквально красной нитью через весь текст, но особенно выпукло обозначена на стр. 6 указанного документа в разделе 7 — "Typing Template Haskell". Поэтому большинство способов их преодоления являются "хаками" тривиально. Если собираетесь упорствовать (и, следовательно, мириться с хаками) — посмотрите, что делает Matt Morrow — http://moonpatio.com/repos, http://code.haskell.org/~morrow. Кстати, для реализации затеи во всей, так сказать, красе ему приходится использовать (как ниже и предположил lomeo) — plugins, а именно, дубину eval оттуда.

И еще. Регулярное вещание анонимом обозначает как минимум неуважение к аудитории. thesz уже намекал на это, однако, даже если Вы и не идентифицируете себя как адресата его намека, я напоминаю, что насчет анонимов в сети существует практически консенсус.
Re[31]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 20.08.09 08:48
Оценка:
Здравствуйте, awson, Вы писали:

A>Не нужно фантазировать. Хотя кое-что изменилось со времен написания основного документа — принципы остались на месте.


Я как раз и утверждаю, что разработчики концепции просто не понимают принципов метапрограммирования.

A> В частности, оттуда можно почерпнуть знание о том, что существенная часть ограничений (включающая все, которые вы ищете способ преодолеть) образовалась не по недоразумению, а вполне себе by design.


И это просиходит исключительно от полного непонимания смысла метапрограммирования.

A> Эта мысль проходит буквально красной нитью через весь текст, но особенно выпукло обозначена на стр. 6 указанного документа в разделе 7 — "Typing Template Haskell".


Я, как мне казалось, совершенно доходчиво объяснил, почему предлагаемая модификация никоим образом не даёт возможностей обойти систему типов, это не unsafePerformIO, в конце концов.

A> Поэтому большинство способов их преодоления являются "хаками" тривиально.


Их не надо преодолевать, блин. Всё делается вполне в рамках имеющейся концепции. Авторы просто не понимают метапрограммирования, вообще. Его в принципе очень мало кто понимает.

A> Если собираетесь упорствовать (и, следовательно, мириться с хаками)


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

A> — посмотрите, что делает Matt Morrow — http://moonpatio.com/repos, http://code.haskell.org/~morrow. Кстати, для реализации затеи во всей, так сказать, красе ему приходится использовать (как ниже и предположил lomeo) — plugins, а именно, дубину eval оттуда.


Ну, во первых, это всё же весьма примитивные варианты применения метапрограммирования. Во вторых, то, что я предлагаю, как раз позволяет обойтись без хаков совсем, и сделать это по православному, типобезопасно и кошерно. Понятно, что об этом лучше писать в haskell-prime, но для начала стоит убедиться, что решение того стоит.

A>И еще. Регулярное вещание анонимом обозначает как минимум неуважение к аудитории.


Меня ваше мнение по этому поводу абсолютно не колышет, представьте себе. Если я и зарегистрируюсь, то забуду на следующей же неделе, как назвался. Я прихожу сюда недостаточно часто, чтобы тратить на регистрацию время. Интересные темы тут появляются раз в квартал. Темы, из которых я мог бы вынести решение нужной мне здесь и сейчас практической задачи — и того реже. Эта тема как раз из их числа.
Re[31]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 20.08.09 10:10
Оценка:
Здравствуйте, awson, Вы писали:

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


A>И еще. Регулярное вещание анонимом обозначает как минимум неуважение к аудитории. thesz уже намекал на это, однако, даже если Вы и не идентифицируете себя как адресата его намека, я напоминаю, что насчет анонимов в сети существует практически консенсус.


Если вам лично не нравятся комментарии анонимных пользователей — вы можете их игнорироровать, либо попросить администрацию ресурса/форума отключить возможность анонимного постинга в подобные разделы. А ваш "консенсус" отдаёт душком. Зачем вы опускаетесь до попыток унизить собеседника?


Cheers!
Re[28]: Как написать виртуальную машину на LISP
От: thesz Россия http://thesz.livejournal.com
Дата: 20.08.09 12:22
Оценка: -1
Здравствуйте, Аноним, Вы писали:

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


А>>> При том, что мы говорим о вполне конкретном случае применения рефлексии — внутри сплайса, для приложения поименованной функции из другого модуля с известной сигнатурой типа. То есть, о работе с API собственно GHC.

T>>Не, ничего такого.
А> В таком случае следует тему сузить. Меня другие варианты не интересуют.

А для меня твой вариант интересен исключительно в развлекательных целях. Проблемы я буду решать по-другому.

T>>Мы говорим о реализации компилятора Лиспа в виде DSEL на Хаскеле.

А> В виде компилируемого EDSL на Хаскеле с произвольным синтаксисом.

Для этого нужен Template Haskell.

Или кодогенерация, но её ты исключил из рассматриваемых решений.

Про заказчика и defmacro ты ловко ввернул. Уважаю.

Хорошо быть своим собственным заказчиком.

T>>Один из вариантов этой реализации — через Template Haskell.

А> Все другие чрезмерно перанальны.

А по-моему, именно твоё решение наиболее страшное.

T>>Поэтому не надо зацикливаться. И поэтому — а почему бы не попробовать ассоциированные типы и классы типов?

А> Потому, что есть условия:
А>- синтаксис EDSL произволен — ну да ладно, никто не запрещает раскрывать сплайс в код на комбинаторах, это не проблема
А>- он должен компилироваться в Хаскелль
А>- должно быть реализовано метапрограммирование в eDSL. Почему? Так хочет заказчик, и не колышет. В спецификации языка есть defmacro — вынь да положь defmacro в реализации.
А>- общий контекст с хост-языком (решене из п.1. тут тоже подходит)

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

А> Ну и в конце концов — это наиболее общее решение. Любые другие будут являться частным случаем этого подхода.


Я так не думаю. Наоборот, задача содержит столько ограничений, что её решение будет наиболее ограниченным.

T>>Так надо попробовать, нет?

А> Не вижу пути.

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

Поэтому мне интересно, как же ты поступишь.

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

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

rewrite rules?..

T>>>>А ты здесь не ошибешься ли?

А>>> Я никогда не исключаю такой возможности. С удовольствием посмотрел бы на пример.
T>>Всё дело в том, что я в Лиспах не разбираюсь.
А> А зря. В этом и разница — я разбираюсь во всём — и в Лиспах, и в Хаскелле, и во всяких там APL-ах и прочих J, и вообще во всём, что только есть.

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

А> И могу выбирать решения из разных миров.


Это я тоже вижу. И вижу упорство, с которым ты натягиваешь решение из Лиспа поверх Хаскеля.

А> А в субкультуре Хаскелля сложились определённые подходы, от которых народ очень не любит отходить.


Я не вижу в этом ничего плохого.

Вот, смотри.

Ты говоришь "нужен defmacro", а на обычный язык это надо перевести "желательна высокая производительность". Или "нужен обобщённый подход". Или как-то ещё.

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

T>>Почему бы тебе не попробовать выразить свою задачу с типами?

А> Почему ты думаешь, что я не пробовал?

Потому, что ты не привёл результатов. Ты сразу схватился за привычный тебе инструмент: метапрограммирование. Причём схватился за него в наиболее привычной тебе манере: кодогенерации.

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

T>> К тому же ты анонимен и мы вольны выбирать из сообщений анонимов на РСДН те, что намерены приписать тебе, а также мы вольны отбрасывать те сообщения, что считаем несущественными.

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

То-то я тут наблюдаю пляски вокруг TH вместо переформулировки задачи.

А>>> Из Лиспа Хаскелль таким образом сделать можно, теперь интересно посмотреть и на обратное преобразование.

T>>I'd like to see that feat.
А> В смысле — Хаскелль на Лиспе?

Процесс! Важен процесс!

Процесс создания Хаскеля на Лиспе!

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

T>>И решаются ассоциированными типами и типами классов.
А> Не решаются. Важное условие — доступ ко всем определениям во время компиляции.

Подумай ещё раз.

T>>Да зачем?

T>>Я использую Хаскель в течении уже 11 лет, из них четыре года в повседневной работе.
T>>Мне метапрограммирование было нужно только первые две недели этих 11 лет и ещё один раз когда-то недавно. А уж DSL да DSEL я понаписал немало.
А> Не отмазка. Я знаю лисперов, которые лет тридцать на Лиспе пишут, и до сих пор не умеют пользоваться как следует метапрограммированием.

Уверяю тебя, я умею.

Я на ассемблере с макросами (ТурбоАссемблер) написал не менее миллиона строк. И макросов там было много, процентов 5.

А> Я уж не говорю о тех, кто тридцать лет пишет на Фортране, и не умеет пользоваться вообще ничем. Я сам — функциональщик с пятнадцатилетним стажем, но метапрограммированием пользуюсь (кстати, преимущественно в реальных, практических задачах) лишь последние лет шесть.


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

Forth и ассемблер.

А>>> Собственно, всё, связанное с языками — как DSL, так и общего назначения. Rule-based systems, CAD-ы, static code analysis с программируемыми правилами, и т.д.

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

Пока не известно про опровержение в виде Atom (HDL), Atom (язык программирования для встроенных систем) и Bluespec.

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

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

Пользователю нужно, чтобы всё работало и было сделано в срок.

Количество этапов пользователя не волнует.

T>>Поэтому либо будут $(func ...), либо из не будет. Последнее доступно только с помощью ассоциированных типов и классов типов.

А> Дались тебе эти ассоциированные типы...

Я недавно научился их использовать!

T>> Вот этот параграф твоего комментария навевает на меня грустные мысли: ты хочешь добиться чего-то с искусственными ограничениями.

А> Это не ограничения. Ограничения — это то, что накладывает на меня Хаскелль. И в этом случае — совершенно безосновательно накладывает. А я вообще не люблю ограничения.

Если ты не любишь ограничения, то зачем ты себя сразу ограничил в формулировке задачи?

T>> С одной стороны, ты желаешь получить "прозрачный для пользователя" код, с другой стороны ты не желаешь вкладывать в цитирование (splice) весь модуль (а при этом получается возможность так сделать).

А> Сплайс — часть того же модуля, где и весь остальной код на Хаскелле присутствует. Почему для него должны быть другие правила видимости определений?

Проверил:
B.hs:12:6:
    Declaration splices are not permitted inside declaration brackets


Не работает.

Ну, и ладно.

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

А> У меня есть на это причины — иерархическое метапрограммирование. Другими способами его реализовать нельзя.

http://www.haskell.org/haskellwiki/GHC/Type_families#An_associated_data_type_example

Я думаю, можно.

А>>> Это чрезмерное усложнение. В нашей игрушечной задаче, например, это потребует изменения самого DSL (Лиспа, то есть). Что само по себе уже подозрительно — ведь хотелось бы иметь возможность реализовать любой DSL.

T>>Приведи пример кода, которого ты хочешь добиться.
А>Грубо говоря, в одном модуле определяем
А>$(thlisptop "(defmacro list args (match args ((head . tail) `(cons ,head (list ,@tail))) (() 'nil)))")

А> а в другом уже можем макрой воспользоваться:

А>$(thlisp "(map (lambda (x) (* x x)) (list 1 2 3 4))")

И что в результате должно получиться?

вот мой вариант в ожидании твоего ответа:
{-# LANGUAGE GADTs, TypeFamilies, EmptyDataDecls, FlexibleInstances #-}

module L where

data Macro_list where
    Macro_list :: Macro_list

data HasMacro
data Expanded

type family AnyMacro a b
type instance AnyMacro HasMacro b = HasMacro
type instance AnyMacro a HasMacro = HasMacro
type instance AnyMacro Expanded Expanded = Expanded

data Lisp hasMacro where
    LAtom :: String -> Lisp hasMacro
    LCon :: Lisp hd -> Lisp tl -> Lisp (AnyMacro hd tl)
    LApp :: LispMacro t => t -> Lisp hd -> Lisp HasMacro

class LispMacro a where
    -- apply a macro.
    apply :: a -> Lisp Expanded -> Lisp Expanded

instance LispMacro (Lisp Expanded) where
    apply hd tl = LCon hd tl

instance LispMacro Macro_list where
    apply Macro_list args = args

expand :: Lisp a -> Lisp Expanded
expand (LAtom a) = LAtom a
expand (LCon a b) = LCon (expand a) (expand b)
expand (LApp t args) = apply t (expand args)


Можно делать reify для каждого символа, что не в области видимости. Но не для самого символа, а для имени ("Macro_"++имя). defmacro name должно создать тип ("Macro_"++name) и реализацию класса LispMacro для него (которая правильным образом отработает раскрытие).

Идея, я думаю, ясна.

А>>>>> Если это EDSL? Препроцессоры городить — это позорная сиплюсплюсщина. Метапрограммирование на то и нужно, чтоб без препроцессоров обходиться.

T>>>>Комбинаторы?
А>>> А если синтаксис Хаскелля не нужен, а нужен совсем другой?
T>>Внешний синтаксис через комбинаторы?
А> Да какой он к бесам внешний. Не, я понимаю, можно извратиться, поднапрячься, и даже что-то похожее на бейсик изобразить — но это именно что извращение. Несистемное решение. Я же ещё не сказал, что к этим eDSL нужна полноценная поддержка от IDE, со всякими там intellisense и прочей ерундой.

Кстати, а ты бейсик, встроенный в Хаскель, видел?

А>>> А если производительности такой интерпретации не хватает?

T>>par/pseq для распараллеливания?
А> Не смешно даже.

И почему конкретно?

А>>> А если кроме родной Хаскелевой системы типов хочется ещё своих сложных проверок добавить?

T>>Внешний DSL?
А> Не вижу существенных отличий в методах реализации внешних DSL от встраиваемых.

А они есть!

Прям, как в анекдоте.

T>>А что за проверки, приведи пример.

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

Кодогенерация.

T>>>>Как много комбинаторных библиотек ты написал?

А>>> До хрена. Например, тот же packrat я делал и на комбинаторах, и метапрограммированием. Второй вариант быстрее ну очень заметно, и при этом позволяет пользоваться приличным синтаксисом.
T>>Задам вопрос по-другому: писал ли ты комбинаторную библиотеку на Хаскеле с использованием {-# INLINE #-} и {-# RULES #-}?
А> Не вижу, чем оно помогло бы в реализации того же Packrat. Я использовал {-# SPECIALIZE ... #- }

Ну, ByteString оно ускорило.

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

А>>> Вот и ворую идеи у сообществ лиспа, немерла, Хаскелля, Axiom и десятков других. Ничего не отдавая им за это.
T>>Это ты так думаешь.
А> Думаю, что ворую? Да нет, знаю, что ворую — вон, работает всё в конкретных проектах, каши не просит. Мне хорошо, а немерлисты о факте воровства даже и не в курсе.

Да, рефлексия у тебя на нуле.

T>>>>К тому же метапрограммирование само по себе не имеет ценности. Оно имеет ценность в качестве одного из инструментов.

А>>> Именно. Но надо знать, как инструментом пользоваться. И это знание имеет ценность.
T>>Это даже не очень и смешно. Зачем кому-то знание о том, как пользоваться не очень ценным (из-за отсутствия развития) инструментом?
А> Хе хе. Вот пока большинство думает, что инструментарий "не очень ценный", у тех немногих, кто знает его ценность, имеется гигантское конкурентное преимущество.

Почему Лисп не используется в описании аппаратуры?

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

А>>> Я не настолько альтруистичен. Но так уж и быть, в этом случае нарушу свои правила.
T>>Уверяю тебя, я всё и всегда делаю ради собственной выгоды.
А> В чём персональная выгода от пропаганды Хаскелля? Кому надо — и так все давно в курсе.

Я не пропагандирую Хаскель, кстати. Я пропагандирую определённые подходы к программированию.

А> Моя выгода от этой дискуссии очевидна — я могу или найти решение в рамках заданных условий, или убедиться, что его нет. Экономия времени, однако.


Да как-то ты не очень и ищешь. И условия выбрал специально тяжёлые.

T>>>>Для этого уже тип не нужен (не может быть двух определений с разными типами в одном модуле). Список используемых модулей нужен, но и всё.

А>>> Тип нужен, чтобы это определение применить.
T>>Тогда — ассоциированные типы.
А> Как это мне поможет динамически вытащить определение по его имени?

Иными словами, ты про подходы Хаскеля к твоей проблеме не знаешь.

Так и запишем, что вот в этой ветке обсуждения аноним противоречит сам себе. Причём, даже внутри одного комментария.

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

А>>> Увы, увы, это ещё не решение. Попробую пропатчить ghc и показать то минимальное изменение, которого достаточно для этой фичи.
T>>Посмотрел на твоё решение повнимательней. Я не думаю, что тебе надо вызывать какую-либо функцию.
А> Ты не понимаешь Лиспа, совершенно. И по этому примеру тем более не сможешь понять, где там надо впихнуть макры.

Уверяю тебя, я очень умный.

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

T>>--например:

T>>[$thlisp|(begin .... print ....)|]
T>>[/haskell]
А> В данном случае толку от них никакого — что кавычки, что палочки, один хрен. Был бы у Хаскелля парсер на PEG — другое дело, можно было бы органично встраивать в него любой синтаксис.

Кстати, а на Лискель ты смотрел?

T>>>>Потому, что API TH под это не заточено. Оно заточено под другие дела.

А>>> Какие же?
T>>Например, foreign генерировать. Всякого рода instance создавать.
А> Примитивщина.

А полезно. Даже для твоих целей.

T>>Что еще...

T>>Текст слегка видоизменять, я думаю. Делать небольшие{/i] языки.
А> А небольшие языки проще всего делать итерационным надстраиванием над языками побольше. Мне нужно иерархическое метапрограммирование, а не просто "foreign генерить".

Да не нужно оно тебе. Не. Нужно.

Это ты собственную важность демонстрируешь, своими рекламациями насчёт "проще всего делать итерационным надстраиванием" и "нужно иерархическое метапрограммирование".

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

Но при этом ты не приводишь данных, почему он самый лучший и эффективный, только анекдоты.

Я, например, подозреваю, что ты не работаешь в команде. Твой код никто не правит. Я подозреваю, более того, что количество ошибок в твоём коде достаточно высоко, а исправление трудоёмко.

Проведи эксперимент, сравни [i]чужую
производительность на разных подходах, оцени количество кода, количество ошибок после проверки кода и после commit в общий репозиторий и только после устойчивого положительного результата настаивай на своём подходе.

T>>>>Помниться, мне макросов хотелось недели две, пока до функций высшего порядка не дошёл.

А>>> Мне никакие функции высшего порядка макросы не заменят. Слишком много интересных применений для макросов я нашел.
T>>Это всё от преждевременной оптимизации.
А> Нет, оптимизация в данном случае совершенно не при чём. Важна семантика.

Тогда генерируй Лисп и раскрывай по необходимости. Лениво, так сказать.

А>>> Они явно от этой проблемы просто отмахнулись.

T>>А почему?
А> По причине непонимания последствий.

Да ты что!

Все не в ногу, а ты в ногу!

Все идиоты, а ты умный.

Или не все идиоты?

Если не все идиоты, то почему они могут игнорировать столь ценимое тобой решение? А почему его игнорируют те, кто про него знают? Не задавался такими вопросами?

А>>> Я когда-то уже обсуждал с SPJ статическое метапрограммирование — так тогда он вообще не понимал, для чего оно может быть нужно в Хаскелле, и не знал, что с ним делают в Лиспе. Потом мнение поменял, но до просветления явно ещё пару шагов требуется. Инерция мышления, однако.

T>>Так то, что с ним делают в Лиспе — получают скорость выполнения, — делают в Хаскеле с помощью оптимизаций.
А> Нет, то, что с ним делают в Лиспе, в Хаскелле не делают вообще.

Нет, то, что ты знаешь о Хаскеле, не даёт тебе права утверждать вообще ничего.

Потому, что в Хаскеле делают по-Хаскельному то, что в Липе делают по-Лисповски.

А про Хаскельный подход ты знаешь чуть более, чем ничего.

T>>Которые оптимизации — как в примере с теми же самыми генериками выше по теме в дискуссии с lomeo, — могут быть применимы где-то ещё, не только в каком-то определённом месте.

А> Кстати да, ast:visit таки очень неплохой пример преимуществ метапрограммирования.

Чем он хуже generic с оптимизациями?
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[29]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 20.08.09 13:13
Оценка: +1
Здравствуйте, thesz, Вы писали:

А>> В таком случае следует тему сузить. Меня другие варианты не интересуют.


T>А для меня твой вариант интересен исключительно в развлекательных целях. Проблемы я буду решать по-другому.


Это существенно ограничивает круг проблем, которые ты способен решать (за приемлемое время).

T>>>Один из вариантов этой реализации — через Template Haskell.

А>> Все другие чрезмерно перанальны.

T>А по-моему, именно твоё решение наиболее страшное.


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

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


Во первых — опять, производительность. Во вторых, это не решает поставленной задачи.

T>Я так не думаю. Наоборот, задача содержит столько ограничений, что её решение будет наиболее ограниченным.


Я уже понял, что ты абсолютно не понимаешь, что такое метапрограммирование.

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


Идиоматический подход мне известен и интереса не представляет. Я его (комбинаторы, rewrite rules, SPECIALIZE, и т.п.) использую там, где в этом есть смысл.

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


T>rewrite rules?..


Не, ты определённо не пытаешься понять, о чём собственно идёт речь.

Нельзя определение rewrite rule сгенерить в template haskell. Кроме того, уж это точно запредельно перанальное решение было бы. На кой хрен мне эти rewrite rules, когда надо определить свой (и предельно тривиальный, следует заметить) macro expander. Который должен срабатывать, кроме всего прочего, на этапе задолго до генерации кода на Haskell.

А>> А зря. В этом и разница — я разбираюсь во всём — и в Лиспах, и в Хаскелле, и во всяких там APL-ах и прочих J, и вообще во всём, что только есть.


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


Да нет, никакого представления ты получить не мог в принципе. ы, Во первых, ты понятия не имеешь ни о Лиспе, ни о метапрограммировании, во вторых — я не дал достаточной информации. У тебя есть какие-то свои забавные представления о том, "как правильно". Всё, что в них не вписывается, всё, что использует незнакомые тебе теории и модели, ты воспринимаешь заведомо как ошибку.

А>> И могу выбирать решения из разных миров.


T>Это я тоже вижу. И вижу упорство, с которым ты натягиваешь решение из Лиспа поверх Хаскеля.


В данном случае я просто не вижу, почему это решение должно противоречить идеологии Хаскелля. И одно только это решение расширяет возможности языка совершенно неограниченным образом. Всякие там примитивные детские rewrite rules рядом с одной этой возможностью — полная фигня (и они поверх этой фичи реализуются тривиально, кстати).

А>> А в субкультуре Хаскелля сложились определённые подходы, от которых народ очень не любит отходить.


T>Я не вижу в этом ничего плохого.


А я считаю это путём в болото.

T>Вот, смотри.


T>Ты говоришь "нужен defmacro",


Я говорю — "в спецификации DSL есть такая фича". Или она реализуема, и тогда наш хост-язык достаточно мощный и общий, или она нереализуема. Я не намерен обсуждать причины включения такой фичи в DSL. В данном случае показательно уже хотя бы то, что реализовать её разумным и понятным способом нельзя. Исключительно по причине упёртости разработчиков TH, не удосужившихся разобраться в сути метапрограммирования.

T> а на обычный язык это надо перевести "желательна высокая производительность". Или "нужен обобщённый подход". Или как-то ещё.


Это уже не важно, в такой постановке.

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


И ни к одному из этих способов TH доступа не даёт. Что следует читать как "TH неполноценен".

T>>>Почему бы тебе не попробовать выразить свою задачу с типами?

А>> Почему ты думаешь, что я не пробовал?

T> Потому, что ты не привёл результатов.


На фига тебе эти результаты? Я решаю совсем другую задачу, игрушечный Lisp — это сведённый до понятного уровня тривиальный пример.

T> Ты сразу схватился за привычный тебе инструмент: метапрограммирование. Причём схватился за него в наиболее привычной тебе манере: кодогенерации.


Альтернативные инструменты этой поставленной задачи не решают.

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


Да, это так. Я то знаю всю мощь этого молотка.

T>То-то я тут наблюдаю пляски вокруг TH вместо переформулировки задачи.


Я уже объяснил, почему я не намерен переформулировать задачу. Не понимаешь до сих пор?

А>>>> Из Лиспа Хаскелль таким образом сделать можно, теперь интересно посмотреть и на обратное преобразование.

T>>>I'd like to see that feat.
А>> В смысле — Хаскелль на Лиспе?

T>Процесс! Важен процесс!


T>Процесс создания Хаскеля на Лиспе!


Не понял пассажа.

Хаскелль на Лиспе (встраиваемый, разделяющий с ним контекст, и т.п.) я сделать могу. Эффективно. И весьма просто. Лисп на Хаскелле с такими же свойствами сделать нельзя. Вот и вся разница.

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

T>>>И решаются ассоциированными типами и типами классов.
А>> Не решаются. Важное условие — доступ ко всем определениям во время компиляции.

T>Подумай ещё раз.


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

А>> Не отмазка. Я знаю лисперов, которые лет тридцать на Лиспе пишут, и до сих пор не умеют пользоваться как следует метапрограммированием.


T>Уверяю тебя, я умею.


Да нет же, не умеешь. Ты даже отдалённого представления не имеешь о том, что это такое.

T>Я на ассемблере с макросами (ТурбоАссемблер) написал не менее миллиона строк. И макросов там было много, процентов 5.


Да какое это на фиг метапрограммирование? Это фигня, банальные макры.

А>> Я уж не говорю о тех, кто тридцать лет пишет на Фортране, и не умеет пользоваться вообще ничем. Я сам — функциональщик с пятнадцатилетним стажем, но метапрограммированием пользуюсь (кстати, преимущественно в реальных, практических задачах) лишь последние лет шесть.


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


То, чем ты пользовался, это никакое не метапрограммирование. Тебя обманули.

T>Forth и ассемблер.


Да уж... Даже не смешно.

T>>>Значит, надо генерировать типобезопасный ЯП, например, Хаскель.

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

T>Пользователю нужно, чтобы всё работало и было сделано в срок.


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

T>Количество этапов пользователя не волнует.


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

T>>>Поэтому либо будут $(func ...), либо из не будет. Последнее доступно только с помощью ассоциированных типов и классов типов.

А>> Дались тебе эти ассоциированные типы...

T>Я недавно научился их использовать!


Я так и подумал.

T>>> Вот этот параграф твоего комментария навевает на меня грустные мысли: ты хочешь добиться чего-то с искусственными ограничениями.

А>> Это не ограничения. Ограничения — это то, что накладывает на меня Хаскелль. И в этом случае — совершенно безосновательно накладывает. А я вообще не люблю ограничения.

T>Если ты не любишь ограничения, то зачем ты себя сразу ограничил в формулировке задачи?


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

T>>> С одной стороны, ты желаешь получить "прозрачный для пользователя" код, с другой стороны ты не желаешь вкладывать в цитирование (splice) весь модуль (а при этом получается возможность так сделать).

А>> Сплайс — часть того же модуля, где и весь остальной код на Хаскелле присутствует. Почему для него должны быть другие правила видимости определений?

T>Проверил:



Ты не понял.

 let a = 2
     $( [| a + a |] )


Для созданного сплайсом кода видимость вполне определена. Какого хрена в неё надо вмешиваться?

T>Я думаю, можно.


Не понимаю.

T>И что в результате должно получиться?


В результате должно получиться ровно то же, что при раскрытии $(thlisp "(map (lambda (x) (* x x)) (cons 1 (cons 2 (cons 3 (cons 4 nil)))))")

T>вот мой вариант в ожидании твоего ответа:


Ок, сейчас посмотрю — на первый взгляд мне не кажется, что это в принципе может вообще работать — reify мне instance не даст.

T>Можно делать reify для каждого символа, что не в области видимости. Но не для самого символа, а для имени ("Macro_"++имя). defmacro name должно создать тип ("Macro_"++name) и реализацию класса LispMacro для него (которая правильным образом отработает раскрытие).


Ты, похоже, не понял, в какой момент отрабатывает expand...

T>Идея, я думаю, ясна.


Всё ещё не ясна.

T>Кстати, а ты бейсик, встроенный в Хаскель, видел?


Конечно же видел. И аналогичной техникой я часто пользуюсь. В данном же случае это не вариант.

T>И почему конкретно?


Потому, что не всё можно параллелить.

А>> Не вижу существенных отличий в методах реализации внешних DSL от встраиваемых.


T>А они есть!


Не-а. Их нет. Внешние DSL проще всего реализуются как частный случай встраиваемых.

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


T>Кодогенерация.


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

T>>>Задам вопрос по-другому: писал ли ты комбинаторную библиотеку на Хаскеле с использованием {-# INLINE #-} и {-# RULES #-}?

А>> Не вижу, чем оно помогло бы в реализации того же Packrat. Я использовал {-# SPECIALIZE ... #- }

T>Ну, ByteString оно ускорило.


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

А>> Моя выгода от этой дискуссии очевидна — я могу или найти решение в рамках заданных условий, или убедиться, что его нет. Экономия времени, однако.


T>Да как-то ты не очень и ищешь. И условия выбрал специально тяжёлые.


Я решаю конкретную задачу — грубо говоря, eval внутри splice. Условия задачи составлены таким образом, чтоб неприменно сводиться к основному требованию. Для чего мне это надо — не существенные детали. Уж поверь — как сделать идиоматически то же самое я прекрасно представляю, и мне не интересно выслушивать предложения пойти этим путём.

А>> Ты не понимаешь Лиспа, совершенно. И по этому примеру тем более не сможешь понять, где там надо впихнуть макры.


T>Уверяю тебя, я очень умный.


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

T>А Лисп не настолько сложный, чтобы его не понять. Как и метапрограммирование.


Именно. Всё очень просто. Но ты не понимаешь — поскольку мыслишь в совершенно иных категориях.

А>> В данном случае толку от них никакого — что кавычки, что палочки, один хрен. Был бы у Хаскелля парсер на PEG — другое дело, можно было бы органично встраивать в него любой синтаксис.


T>Кстати, а на Лискель ты смотрел?


Смотрел, конечно же. У меня несколько другая задача — не Хаскелль с синтаксисом Лиспа, а встроенный в Хаскелль полноценный Лисп (то есть, eager, dynamic, и всё такое прочее).

А>> А небольшие языки проще всего делать итерационным надстраиванием над языками побольше. Мне нужно иерархическое метапрограммирование, а не просто "foreign генерить".


T>Да не нужно оно тебе. Не. Нужно.


Нужно-нужно.

T>Это ты собственную важность демонстрируешь, своими рекламациями насчёт "проще всего делать итерационным надстраиванием" и "нужно иерархическое метапрограммирование".


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

T>Ты не можешь от этого отказаться потому, что считаешь твой подход самым лучшим и эффективным. Соответственно, твоё мнение самое важное.


Для моих задач мой подход работает лучше всех прочих. Меня не интересуют другие задачи.

T>Но при этом ты не приводишь данных, почему он самый лучший и эффективный, только анекдоты.


Я же уже сказал — спорить и убеждать я не намерен.

T>Я, например, подозреваю, что ты не работаешь в команде. Твой код никто не правит.


Неверное подозрение.

T> Я подозреваю, более того, что количество ошибок в твоём коде достаточно высоко, а исправление трудоёмко.


Абсолютно неверный вывод.

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

T>Проведи эксперимент, сравни чужую производительность на разных подходах, оцени количество кода, количество ошибок после проверки кода и после commit в общий репозиторий и только после устойчивого положительного результата настаивай на своём подходе.


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

А>> Нет, оптимизация в данном случае совершенно не при чём. Важна семантика.


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


Второе условие — код надо скрыть.

T>Если не все идиоты, то почему они могут игнорировать столь ценимое тобой решение? А почему его игнорируют те, кто про него знают? Не задавался такими вопросами?


Те, кто про него знают, Хаскеллем не пользуются.

T>А про Хаскельный подход ты знаешь чуть более, чем ничего.


Ну ну. Посмешил.

А>> Кстати да, ast:visit таки очень неплохой пример преимуществ метапрограммирования.


T>Чем он хуже generic с оптимизациями?


Компактнее. Услойчивее к изменениям структуры. Лучше подходит для тривиальных преобразований.
Re[30]: Как написать виртуальную машину на LISP
От: FR  
Дата: 20.08.09 13:38
Оценка:
Здравствуйте, Аноним, Вы писали:

А> Ну, твоего кода я вообще не видел, но представление имею, как он может выглядеть. Человек, принципиально не понимающий Лиспа в частности и метапрограммирования вообще, может та-акого понаписать...


Человек плотно писавший на форте не может не понимать метапрограммирования.
Re[31]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 20.08.09 13:51
Оценка:
Здравствуйте, FR, Вы писали:

FR>Человек плотно писавший на форте не может не понимать метапрограммирования.


В форте не доступно серьёзное метапрограммирование. Так, макропрограммирование только.
Re[32]: Как написать виртуальную машину на LISP
От: FR  
Дата: 20.08.09 13:52
Оценка:
Здравствуйте, Аноним, Вы писали:

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


FR>>Человек плотно писавший на форте не может не понимать метапрограммирования.


А> В форте не доступно серьёзное метапрограммирование. Так, макропрограммирование только.


И чем определяется серъезность?
Re[30]: Как написать виртуальную машину на LISP
От: thesz Россия http://thesz.livejournal.com
Дата: 20.08.09 16:02
Оценка:
Здравствуйте, Аноним, Вы писали:

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


T>>А для меня твой вариант интересен исключительно в развлекательных целях. Проблемы я буду решать по-другому.

А> Это существенно ограничивает круг проблем, которые ты способен решать (за приемлемое время).

Да ты чо!

Давай возьмём любое приложение и посмотрим, как много там можно приложить метапрограммирования.

T>>>>Один из вариантов этой реализации — через Template Haskell.

А>>> Все другие чрезмерно перанальны.
T>>А по-моему, именно твоё решение наиболее страшное.
А> Ну, твоего кода я вообще не видел, но представление имею, как он может выглядеть. Человек, принципиально не понимающий Лиспа в частности и метапрограммирования вообще, может та-акого понаписать...

Наверное, что-то простое и наиболее подходящее к проблеме? Уж точно без метапрограммирования там, где оно не нужно. И с метапрограммированием там, где нужно.

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

А> Во первых — опять, производительность. Во вторых, это не решает поставленной задачи.

Производительность — см. другие способы ускорения программ.

А то, что не решает поставленной задачи, так это задача так поставлена, что её хрен решить.

T>>Я так не думаю. Наоборот, задача содержит столько ограничений, что её решение будет наиболее ограниченным.

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

В свете количества твоих ошибок это выглядит, скорее, как комплимент.

А>>> А зря. В этом и разница — я разбираюсь во всём — и в Лиспах, и в Хаскелле, и во всяких там APL-ах и прочих J, и вообще во всём, что только есть.

T>>Про степень твоего знания Хаскеля и типичных для него решений я получил более, чем достаточную информацию.
А> Да нет, никакого представления ты получить не мог в принципе. ы, Во первых, ты понятия не имеешь ни о Лиспе, ни о метапрограммировании, во вторых — я не дал достаточной информации.

Ты не переживай.

Ну, не знаю я Лисп,

А> У тебя есть какие-то свои забавные представления о том, "как правильно". Всё, что в них не вписывается, всё, что использует незнакомые тебе теории и модели, ты воспринимаешь заведомо как ошибку.


А>>> И могу выбирать решения из разных миров.


T>>Это я тоже вижу. И вижу упорство, с которым ты натягиваешь решение из Лиспа поверх Хаскеля.


А> В данном случае я просто не вижу, почему это решение должно противоречить идеологии Хаскелля. И одно только это решение расширяет возможности языка совершенно неограниченным образом. Всякие там примитивные детские rewrite rules рядом с одной этой возможностью — полная фигня (и они поверх этой фичи реализуются тривиально, кстати).


А>>> А в субкультуре Хаскелля сложились определённые подходы, от которых народ очень не любит отходить.


T>>Я не вижу в этом ничего плохого.


А> А я считаю это путём в болото.


T>>Вот, смотри.


T>>Ты говоришь "нужен defmacro",


А> Я говорю — "в спецификации DSL есть такая фича". Или она реализуема, и тогда наш хост-язык достаточно мощный и общий, или она нереализуема. Я не намерен обсуждать причины включения такой фичи в DSL. В данном случае показательно уже хотя бы то, что реализовать её разумным и понятным способом нельзя. Исключительно по причине упёртости разработчиков TH, не удосужившихся разобраться в сути метапрограммирования.


T>> а на обычный язык это надо перевести "желательна высокая производительность". Или "нужен обобщённый подход". Или как-то ещё.


А> Это уже не важно, в такой постановке.


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


А> И ни к одному из этих способов TH доступа не даёт. Что следует читать как "TH неполноценен".


T>>>>Почему бы тебе не попробовать выразить свою задачу с типами?

А>>> Почему ты думаешь, что я не пробовал?

T>> Потому, что ты не привёл результатов.


А> На фига тебе эти результаты? Я решаю совсем другую задачу, игрушечный Lisp — это сведённый до понятного уровня тривиальный пример.


T>> Ты сразу схватился за привычный тебе инструмент: метапрограммирование. Причём схватился за него в наиболее привычной тебе манере: кодогенерации.


А> Альтернативные инструменты этой поставленной задачи не решают.


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


А> Да, это так. Я то знаю всю мощь этого молотка.


T>>То-то я тут наблюдаю пляски вокруг TH вместо переформулировки задачи.


А> Я уже объяснил, почему я не намерен переформулировать задачу. Не понимаешь до сих пор?


А>>>>> Из Лиспа Хаскелль таким образом сделать можно, теперь интересно посмотреть и на обратное преобразование.

T>>>>I'd like to see that feat.
А>>> В смысле — Хаскелль на Лиспе?

T>>Процесс! Важен процесс!


T>>Процесс создания Хаскеля на Лиспе!


А> Не понял пассажа.


А> Хаскелль на Лиспе (встраиваемый, разделяющий с ним контекст, и т.п.) я сделать могу. Эффективно. И весьма просто. Лисп на Хаскелле с такими же свойствами сделать нельзя. Вот и вся разница.


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

T>>>>И решаются ассоциированными типами и типами классов.
А>>> Не решаются. Важное условие — доступ ко всем определениям во время компиляции.

T>>Подумай ещё раз.


А> Не строй из себя гуру — тебе это не идёт. Вместо попыток сделать вид, что знаешь тайное решение и понимаешь, что надо делать — привёл бы свой вариант. Я бы показал, почему это решением не является.


А>>> Не отмазка. Я знаю лисперов, которые лет тридцать на Лиспе пишут, и до сих пор не умеют пользоваться как следует метапрограммированием.


T>>Уверяю тебя, я умею.


А> Да нет же, не умеешь. Ты даже отдалённого представления не имеешь о том, что это такое.


T>>Я на ассемблере с макросами (ТурбоАссемблер) написал не менее миллиона строк. И макросов там было много, процентов 5.

А> Да какое это на фиг метапрограммирование? Это фигня, банальные макры.

CREATE..DOES> банальные макры?

Великолепно.

Надо тебя ещё на что-нибудь раскрутить.

А>>> Я уж не говорю о тех, кто тридцать лет пишет на Фортране, и не умеет пользоваться вообще ничем. Я сам — функциональщик с пятнадцатилетним стажем, но метапрограммированием пользуюсь (кстати, преимущественно в реальных, практических задачах) лишь последние лет шесть.

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

http://forth.rhub.firstvds.ru/books.php
К.ТАУНСЕНД, Д.ФОХТ. ПРОЕКТИРОВАНИЕ И ПРОГРАММНАЯ РЕАЛИЗАЦИЯ ЭКСПЕРТНЫХ СИСТЕМ НА ПЕРСОНАЛЬНЫХ ЭВМ. Перевод с английскогоВ.А.Кондратенко, С. В. Трубицына. Предисловие Г.С.Осипова.

Там рассказано, как парой килобайт кода на Форте сделать Лисп, да со скобочками, а не просто так, а на Лиспе потом написать Пролог, на котором формулировать правила экспертных систем.

T>>Forth и ассемблер.

А> Да уж... Даже не смешно.

Как я понимаю, ты и про Форт не очень много знаешь.

T>>>> Вот этот параграф твоего комментария навевает на меня грустные мысли: ты хочешь добиться чего-то с искусственными ограничениями.

А>>> Это не ограничения. Ограничения — это то, что накладывает на меня Хаскелль. И в этом случае — совершенно безосновательно накладывает. А я вообще не люблю ограничения.
T>>Если ты не любишь ограничения, то зачем ты себя сразу ограничил в формулировке задачи?
А> Потому что этот подход снимает вообще любые ограничения, сразу. Это способ избавиться от ограничений навсегда.

Про фальсифицируемость и Карла Поппера ты не слышал, нет?

T>>И что в результате должно получиться?

А> В результате должно получиться ровно то же, что при раскрытии $(thlisp "(map (lambda (x) (* x x)) (cons 1 (cons 2 (cons 3 (cons 4 nil)))))")
T>>вот мой вариант в ожидании твоего ответа:
А> Ок, сейчас посмотрю — на первый взгляд мне не кажется, что это в принципе может вообще работать — reify мне instance не даст.

Вызов instance тебе даст упрощение, которое будет проводиться при вызове того, чему присвоили $(thlisp ...). Вместо вызова макроопределения (macroname macroArgs) (на Хаскеле LCon macroName macroArgs) per se ты должен сделать THLisp.expand (LApp Macro_macroname macroArgs). Macro_macroname раскроет своё тело с подстановкой macroArgs в момент обращения к значению.

T>>Можно делать reify для каждого символа, что не в области видимости. Но не для самого символа, а для имени ("Macro_"++имя). defmacro name должно создать тип ("Macro_"++name) и реализацию класса LispMacro для него (которая правильным образом отработает раскрытие).

А> Ты, похоже, не понял, в какой момент отрабатывает expand...

В момент обращения.

T>>Идея, я думаю, ясна.

А> Всё ещё не ясна.

Здесь я умываю руки.

Я и так рассказал много больше, чем услышал. Хотя надеялся на обратное, тем более, что начальное заявление было твоим
Автор:
Дата: 12.08.09
(надеюсь, что твоим, а то вас анонимов не поймёшь).

T>>Кстати, а ты бейсик, встроенный в Хаскель, видел?

А> Конечно же видел. И аналогичной техникой я часто пользуюсь. В данном же случае это не вариант.

А про такой вариант
Автор: geniepro
Дата: 13.02.09
?

Может, что интересное для себя извлечёшь.

T>>И почему конкретно?

А> Потому, что не всё можно параллелить.

То, что работает долго, обычно можно.

А>>> Не вижу существенных отличий в методах реализации внешних DSL от встраиваемых.

T>>А они есть!
А> Не-а. Их нет. Внешние DSL проще всего реализуются как частный случай встраиваемых.

Ты свои комментарии не читаешь, эт точно.

Так проколоться в трех предложениях суммарным объёмов 12 слов...

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

T>>Кодогенерация.
А> Которая является частным случаем метапрограммирования.

Или наоборот.

А>>> Ты не понимаешь Лиспа, совершенно. И по этому примеру тем более не сможешь понять, где там надо впихнуть макры.

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

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

Брюс Ли, к примеру, приседал со штангой, подбирая вес так, чтобы выполнить 2 подхода по 12 повторений.

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

О практическом уме говорит способность выдать правильное и применимое решение. Очень показательно отсутствие этих двух пунктах в твоём параграфе выше.

T>>А Лисп не настолько сложный, чтобы его не понять. Как и метапрограммирование.

А> Именно. Всё очень просто. Но ты не понимаешь — поскольку мыслишь в совершенно иных категориях.

Я понимаю.

Но я понимаю, также, что не все задачи требуют своего ЯП с настолько своим синтаксисом, что надо столь сильно изощряться.

На моей памяти таких задач раз, два и обчёлся.

T>>Ты не можешь от этого отказаться потому, что считаешь твой подход самым лучшим и эффективным. Соответственно, твоё мнение самое важное.

А> Для моих задач мой подход работает лучше всех прочих. Меня не интересуют другие задачи.

Ну, как бы это сказать-то...

Мне бы хотелось, по результатам этой дискуссии, твоего признания, что ты не всё понимаешь в Хаскеле, Форте и других языках.

Из этого будет следовать вывод, что твой текущий подход не самый лучший, но я его опущу.

T>> Я подозреваю, более того, что количество ошибок в твоём коде достаточно высоко, а исправление трудоёмко.

А> Абсолютно неверный вывод.

Это не только мой вывод, это вывод бывших лисперов.

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


Ты, вон, приведи код функции, что не даёт подать на свой вход код с нераскрытыми макросами.

T>>Проведи эксперимент, сравни чужую производительность на разных подходах, оцени количество кода, количество ошибок после проверки кода и после commit в общий репозиторий и только после устойчивого положительного результата настаивай на своём подходе.

А> У меня достаточно данных — мой подход позволяет новому человеку быстро въехать в процесс, и защищён от глупых ошибок. Главное — он тупой. Очень тупой, тупее придумать нельзя. Твой же подход — заумный и требует напряга мозгов. Лично я мозгами пользоваться вообще не люблю.

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

Чем для структурирования программ пользуешься ты?

А>>> Нет, оптимизация в данном случае совершенно не при чём. Важна семантика.

T>>Тогда генерируй Лисп и раскрывай по необходимости. Лениво, так сказать.
А> Второе условие — код надо скрыть.

У тебя условия появляются по ходу дискуссии.

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

"А вот тебе ещё условие. А вот посмотрим, как ты с ним справишься. Ага, не справился! Вот и я не могу. Да ты, оказывается, не умней меня."

Давай так.

Идиоматический подход в Хаскеле таков: сперва надо получить хоть какую-то реализацию просто на Хаскеле, затем постепенно надо переносить её в TH или комбинаторы, вплоть до получения необходимой формы.

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

T>>Если не все идиоты, то почему они могут игнорировать столь ценимое тобой решение? А почему его игнорируют те, кто про него знают? Не задавался такими вопросами?

А> Те, кто про него знают, Хаскеллем не пользуются.

То есть, ты Хаскелем не пользуешься?

Ты не читаешь свои комментарии.

T>>А про Хаскельный подход ты знаешь чуть более, чем ничего.

А> Ну ну. Посмешил.

А как иначе назвать то, что мы видим выше по обсуждению?

А>>> Кстати да, ast:visit таки очень неплохой пример преимуществ метапрограммирования.

T>>Чем он хуже generic с оптимизациями?
А> Компактнее.

Сравни код на generic с кодом на ast:visit.

А> Услойчивее к изменениям структуры.


Приведи примеры большей устойчивости.

А> Лучше подходит для тривиальных преобразований.


Ой.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[31]: Как написать виртуальную машину на LISP
От: Аноним  
Дата: 20.08.09 16:59
Оценка: 2 (1)
Здравствуйте, thesz, Вы писали:

T>>>А для меня твой вариант интересен исключительно в развлекательных целях. Проблемы я буду решать по-другому.

А>> Это существенно ограничивает круг проблем, которые ты способен решать (за приемлемое время).

T>Да ты чо!


Да-да.

T>Давай возьмём любое приложение и посмотрим, как много там можно приложить метапрограммирования.


Сложно найти такую задачу, которая от метапрограммирования не выигрывала бы. Поскольку метапрограммирование — лучший способ реализации language oriented programming, да да, именно метапрограммирование, а не ФВП.

А>> Ну, твоего кода я вообще не видел, но представление имею, как он может выглядеть. Человек, принципиально не понимающий Лиспа в частности и метапрограммирования вообще, может та-акого понаписать...


T>Наверное, что-то простое и наиболее подходящее к проблеме?


Вот про "простое" не поверю. Простое — это прямолинейное. Ты же ищешь сложные обходные пути, лишь бы оно "идиоматично" получилось.

Т> Уж точно без метапрограммирования там, где оно не нужно. И с метапрограммированием там, где нужно.


Да не знаешь ты, где оно нужно, к сожалению.

T>Производительность — см. другие способы ускорения программ.


Другие способы слишком дорогостоящие. Дешевле кодогенерации ничего пока не придумали.

T>А то, что не решает поставленной задачи, так это задача так поставлена, что её хрен решить.


Что ж ты мне мозги пудришь, про эти ассоциированные типы? Я же сразу сказал, что они не являются ни разу решением этой задачи.

T>>>Я так не думаю. Наоборот, задача содержит столько ограничений, что её решение будет наиболее ограниченным.

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

T>В свете количества твоих ошибок это выглядит, скорее, как комплимент.


?!? Ошибок я не делал. Я выразил сомнение в надёжности reify — и тут же признал, что был неправ. Во всём остальном я ни разу не ошибся. Ты видишь то, что хочешь видить, а не что есть на самом деле.

T>>>Я на ассемблере с макросами (ТурбоАссемблер) написал не менее миллиона строк. И макросов там было много, процентов 5.

А>> Да какое это на фиг метапрограммирование? Это фигня, банальные макры.

T>CREATE..DOES> банальные макры?


Именно, именно. Банальнее некуда. У модели Форта есть очень серьёзные ограничения, делающие метапрограммирование на нём неоправданно сложным.

T>Там рассказано, как парой килобайт кода на Форте сделать Лисп, да со скобочками, а не просто так, а на Лиспе потом написать Пролог, на котором формулировать правила экспертных систем.


Да делал я Лисп на Форте. Все делали. И Форт на Macro32 делал, и Лисп на Форте, и Пролог на Лиспе... Только фигня это всё. Неоправданно сложно. Моментальный качественный переход вместо итеративного, инкрементального роста. Ну а Пролог на Лиспе — это уже да, это легко и просто. Когда нормальное метапрограммирование есть, генерить WAM можно элементарно. Правда, Пролог туп, компиляцию в WAM можно и средствами Форта сделать довольно таки адекватно и читабельно, хоть и не сравнимо с простотой реализации того же самого средствами Лиспа.

T>>>Forth и ассемблер.

А>> Да уж... Даже не смешно.

T>Как я понимаю, ты и про Форт не очень много знаешь.


Неверно понимаешь. Точнее, совсем ни фига не понимаешь.

T>>>Если ты не любишь ограничения, то зачем ты себя сразу ограничил в формулировке задачи?

А>> Потому что этот подход снимает вообще любые ограничения, сразу. Это способ избавиться от ограничений навсегда.

T>Про фальсифицируемость и Карла Поппера ты не слышал, нет?


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

T>Вызов instance тебе даст упрощение, которое будет проводиться при вызове того, чему присвоили $(thlisp ...).


Я так и понял, что ты даже не осилил понять того моего примитивного кода. Твоё решение даже так, как ты говоришь, работать не будет. Вставь там pprint, посмотри, что на выходе $(thlisp ...).

T> Вместо вызова макроопределения (macroname macroArgs) (на Хаскеле LCon macroName macroArgs) per se ты должен сделать THLisp.expand (LApp Macro_macroname macroArgs). Macro_macroname раскроет своё тело с подстановкой macroArgs в момент обращения к значению.


На кой мне эти списки во время исполнения? Макры должны раскрываться во время компиляции. Точка. Другие решения — извращение, неоправданное и нелепое.

А>> Ты, похоже, не понял, в какой момент отрабатывает expand...


T>В момент обращения.


Это уже тогда не expand, это фигня какая-то.

T>>>Идея, я думаю, ясна.

А>> Всё ещё не ясна.

T>Здесь я умываю руки.


Мне не ясна не идея, а, скажем так, твоё странное упорство в её отстаивании.

T>Я и так рассказал много больше, чем услышал. Хотя надеялся на обратное, тем более, что начальное заявление было твоим
Автор:
Дата: 12.08.09
(надеюсь, что твоим, а то вас анонимов не поймёшь).


Что именно хотел? Компилятор той VM на TH и на Лиспе? До этого у меня руки ещё не дошли. Сделаю, как время будет. Вот может сегодня вечером и сделаю.

T>А про такой вариант
Автор: geniepro
Дата: 13.02.09
?


T>Может, что интересное для себя извлечёшь.


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

T>>>И почему конкретно?

А>> Потому, что не всё можно параллелить.

T>То, что работает долго, обычно можно.


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

T>>>Кодогенерация.

А>> Которая является частным случаем метапрограммирования.

T>Или наоборот.


См. определение метапрограммирования.

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


T>Ты, видимо, не знаешь, что верткие хоккеисты, разящие боксёры, быстрые спринтеры и даже молниеносный Брюс Ли — все они развивали и развивают мышечную силу.


До определённого предела. Если перекачаешься, то потом гибкость вернуть уже очень сложно.

T>Если возвращаться к теме мышления, то ум прямо пропорционален скорости перебора вариантов (скорости решения простых задач). Умение выдать быстрое и неожиданное решение говорит именно об уме, поэтому не стоит себя принижать.


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

T>О практическом уме говорит способность выдать правильное и применимое решение. Очень показательно отсутствие этих двух пунктах в твоём параграфе выше.


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

T>>>А Лисп не настолько сложный, чтобы его не понять. Как и метапрограммирование.

А>> Именно. Всё очень просто. Но ты не понимаешь — поскольку мыслишь в совершенно иных категориях.

T>Я понимаю.


Нет, не понимаешь. Иначе бы не городил expand, который раскрывается при первом вызове.

T>Но я понимаю, также, что не все задачи требуют своего ЯП с настолько своим синтаксисом, что надо столь сильно изощряться.


Столь сильно изощряться приходится только в TH. По причине его неприспособленности к таким вещам. На Лиспе изощряться не приходится.

T>На моей памяти таких задач раз, два и обчёлся.


Ну повезло, значит.

T>Мне бы хотелось, по результатам этой дискуссии, твоего признания, что ты не всё понимаешь в Хаскеле, Форте и других языках.


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

T>Из этого будет следовать вывод, что твой текущий подход не самый лучший, но я его опущу.


Для TH — конечно не самый лучший. Потому как TH крив. А я хочу его улучшить — так, чтобы в Хаскелле, кроме прочих, работал бы ещё и этот подход.

T>>> Я подозреваю, более того, что количество ошибок в твоём коде достаточно высоко, а исправление трудоёмко.

А>> Абсолютно неверный вывод.

T>Это не только мой вывод, это вывод бывших лисперов.


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

Показать, например, реализацию pattern matching в Лиспе, сделанную таким способом? Или, например, list comprehensions? Или реализацию инфиксного синтаксиса?

T>Ты, вон, приведи код функции, что не даёт подать на свой вход код с нераскрытыми макросами.


Это вообще как? Макросы раскрываются компилятором, какой такой вообще "код" может быть подан на вход функции в рантайме?

T>Строгая типизация была придумана для оптимизаций, а сейчас используется для структурирования программ.


Интересная точка зрения. Пруфлинк? С Лукой Карделли я знаком, он таких странностей не говорил и не писал. Кто больший авторитет в типах — я не в курсе.

T>Чем для структурирования программ пользуешься ты?


Семантикой. Я довожу идею language oriented programming до абсолюта — каждой задаче свой язык, всегда. Как бы мелка задача не была. Системы типов — лишь частный случай такого подхода.

А>>>> Нет, оптимизация в данном случае совершенно не при чём. Важна семантика.

T>>>Тогда генерируй Лисп и раскрывай по необходимости. Лениво, так сказать.
А>> Второе условие — код надо скрыть.

T>У тебя условия появляются по ходу дискуссии.


Да ну? Я это условие сформулировал в самом начале ещё, читай внимательнее. Я отвечал на вопрос, почему нельзя код динамически генерить, и сказал, что это минимально приемлемая защита от reverse engineering.

T>Это верный признак того, что мой оппонент пытается выставить меня не дураком, нет, но человеком заведомо не умнее себя.


Скорее это признак того, что кое-кто читает не очень внимательно.

T>"А вот тебе ещё условие. А вот посмотрим, как ты с ним справишься. Ага, не справился! Вот и я не могу. Да ты, оказывается, не умней меня."


Условие, что весь код генерится статически и во время компиляции было выскзано в самом начале. Далее следовали объяснения, почему такое условие вводится — но они, собственно, и не нужны. Ты всё время пытаешься условие расширить, и решить другую задачу. Мне же другие решения не интересны, я их и так прекрасно знаю.

T> Идиоматический подход в Хаскеле таков: сперва надо получить хоть какую-то реализацию просто на Хаскеле, затем постепенно надо переносить её в TH или комбинаторы, вплоть до получения необходимой формы.


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

T>Изначально у тебя отдельно стоящего Лиспа не было. Поэтому и всех условий не было видно.


Ну почему же — с начала я сделал компилятор Лиспа без макр. И после этого уже поставил задачу — в рамках конкретно этого подхода добавить defmacro.

T> Поэтому ты и топчешься на месте, путаясь в TH, а не в переносе уже готовой функциональности в средства TH.


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

А>> Те, кто про него знают, Хаскеллем не пользуются.


T>То есть, ты Хаскелем не пользуешься?


Пользуюсь не эксклюзивно. Там, где мне нужно метапрограммирование, я им не пользуюсь.

T>Ты не читаешь свои комментарии.


Не буквоедствуй. Я вполне нормально объяснил, почему у TH так мало пользователей и практических применений.

А>>>> Кстати да, ast:visit таки очень неплохой пример преимуществ метапрограммирования.

T>>>Чем он хуже generic с оптимизациями?
А>> Компактнее.

T>Сравни код на generic с кодом на ast:visit.


Уже ранее приводившийся тут код для lambda lifting и обработки lexical scope — заведомо и очевидно компактнее.

А>> Услойчивее к изменениям структуры.


T>Приведи примеры большей устойчивости.


Измени определение AST для той самой задачи про lambda lifting, и посмотри.

А>> Лучше подходит для тривиальных преобразований.


T>Ой.


Я же объяснил, почему нужны именно тривиальные преобразования. И почему они должны быть простыми и читабельными.
Re[32]: Как написать виртуальную машину на LISP
От: frontsquat  
Дата: 20.08.09 18:06
Оценка: +1
Здравствуйте, Аноним, Вы писали:

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


А> Показать, например, реализацию pattern matching в Лиспе, сделанную таким способом? Или, например, list comprehensions? Или реализацию инфиксного синтаксиса?


Покажи, как время будет.
Re[32]: Как написать виртуальную машину на LISP
От: thesz Россия http://thesz.livejournal.com
Дата: 20.08.09 21:33
Оценка:
Здравствуйте, Аноним, Вы писали:

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


T>>Давай возьмём любое приложение и посмотрим, как много там можно приложить метапрограммирования.

А> Сложно найти такую задачу, которая от метапрограммирования не выигрывала бы. Поскольку метапрограммирование — лучший способ реализации language oriented programming, да да, именно метапрограммирование, а не ФВП.

То-то весь более-менее прогрессивный мир стремится в область зависимых типов...

А>>> Ну, твоего кода я вообще не видел, но представление имею, как он может выглядеть. Человек, принципиально не понимающий Лиспа в частности и метапрограммирования вообще, может та-акого понаписать...

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

An idiom is a phrase whose meaning cannot be determined by the literal definition of the phrase itself, but refers instead to a figurative meaning that is known only through common use. (C) Wikipedia


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

Иными словами, наиболее прямое решение.

Например, не стоит писать компилирующий вариант Лиспа на Си с использованием тамошнего метапрограммирования.

Т>> Уж точно без метапрограммирования там, где оно не нужно. И с метапрограммированием там, где нужно.

А> Да не знаешь ты, где оно нужно, к сожалению.

Без указаний, что и где я не знаю, это бессмысленное заявление. Особенно с учётом широты термина "метапрограммирование".

T>>А то, что не решает поставленной задачи, так это задача так поставлена, что её хрен решить.

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

А почему они не являются решением этой задачи? Что мешает их использовать?

T>>>>Я так не думаю. Наоборот, задача содержит столько ограничений, что её решение будет наиболее ограниченным.

А>>> Я уже понял, что ты абсолютно не понимаешь, что такое метапрограммирование.
T>>В свете количества твоих ошибок это выглядит, скорее, как комплимент.
А> ?!? Ошибок я не делал. Я выразил сомнение в надёжности reify — и тут же признал, что был неправ. Во всём остальном я ни разу не ошибся. Ты видишь то, что хочешь видить, а не что есть на самом деле.

Либо ты не хочешь видеть того, что пошатнёт тебя в твоих глазах.

Смотри, ты сказал, что reify неприменим по такой-то причине, исправился и продолжил утверждать, что Template Haskell неприменим. Вместо поиска решения с использованием, возможно, других средств Хаскеля.

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

T>>>>Я на ассемблере с макросами (ТурбоАссемблер) написал не менее миллиона строк. И макросов там было много, процентов 5.

А>>> Да какое это на фиг метапрограммирование? Это фигня, банальные макры.
T>>CREATE..DOES> банальные макры?
А> Именно, именно. Банальнее некуда.

А семантику пары CREATE..DOES> не расскажешь ли?

А> У модели Форта есть очень серьёзные ограничения, делающие метапрограммирование на нём неоправданно сложным.


И какие же?

T>>>>Forth и ассемблер.

А>>> Да уж... Даже не смешно.
T>>Как я понимаю, ты и про Форт не очень много знаешь.
А> Неверно понимаешь. Точнее, совсем ни фига не понимаешь.

Тут какая ситуация.

Я и другие говорю, что в Форте метапрограммирование есть. Мощное, хорошее метапрограммирование.

Ты говоришь, что его там нет.

Я бы согласился с тобой, если бы другие говорили так же, как ты.

Здесь всё та же ситуация, когда ты идёшь в ногу, а все не в ногу.

T>>>>Если ты не любишь ограничения, то зачем ты себя сразу ограничил в формулировке задачи?

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

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

T>>Вызов instance тебе даст упрощение, которое будет проводиться при вызове того, чему присвоили $(thlisp ...).

А> Я так и понял, что ты даже не осилил понять того моего примитивного кода. Твоё решение даже так, как ты говоришь, работать не будет.

Почему?

А> Вставь там pprint, посмотри, что на выходе $(thlisp ...).


Если я правильно понимаю, изменения минимальны.

Измени сигнатуру чего у меня там было в классе с Lisp ty на IO (Lisp ty), и делов. И expand тоже надо будет поменять.

Если это не проходит, то почему?

T>> Вместо вызова макроопределения (macroname macroArgs) (на Хаскеле LCon macroName macroArgs) per se ты должен сделать THLisp.expand (LApp Macro_macroname macroArgs). Macro_macroname раскроет своё тело с подстановкой macroArgs в момент обращения к значению.

А> На кой мне эти списки во время исполнения? Макры должны раскрываться во время компиляции. Точка. Другие решения — извращение, неоправданное и нелепое.

Ну, уговорил.

Заведи IORef с макросами.

import System.IO
import Data.IORef
import System.IO.Unsafe

{-# NOINLINE topDecls #-}
topDecls :: IORef [String]
topDecls = unsafePerformIO $ newIORef []

compile_top :: LispTop -> DecQ
compile_top (LAdefun nm args body) = do
    loc <- location
    runIO $ modifyIORef topDecls (\s -> (loc_module loc++'.':nm):s)
    funD (mkName ("lisp_" ++ nm))
         [(clause [(listP (map (\n -> varP (mkName n)) args))]
                      (normalB (compile_expr body)) [])]

thAllTopDecls :: ExpQ
thAllTopDecls = do
    allDecls <- runIO $ readIORef topDecls
    return $ LitE $ StringL $ show allDecls

-- там, где main:
main = do
   ...
   putStrLn $(thAllTopDecls) -- покажет ["Main.fact"]


В энтот IORef можно запендюривать всё, что душе угодно.

Например, код макросов супротив их имени.

А>>> Ты, похоже, не понял, в какой момент отрабатывает expand...

T>>В момент обращения.
А> Это уже тогда не expand, это фигня какая-то.

Чем отличается?

T>>>>Идея, я думаю, ясна.

А>>> Всё ещё не ясна.
T>>Здесь я умываю руки.
А> Мне не ясна не идея, а, скажем так, твоё странное упорство в её отстаивании.

Из нас двоих хоть какие-то мысли в направлении решения тобой поставленной задачи выражаю я один.

Ты просто упорствуешь в тезисе "метапрограммирование — это круто!" а я предлагаю решения.

По-моему, я круче и поэтому метапрограммирование — отстой.

T>>Я и так рассказал много больше, чем услышал. Хотя надеялся на обратное, тем более, что начальное заявление было твоим
Автор:
Дата: 12.08.09
(надеюсь, что твоим, а то вас анонимов не поймёшь).

А> Что именно хотел? Компилятор той VM на TH и на Лиспе? До этого у меня руки ещё не дошли. Сделаю, как время будет. Вот может сегодня вечером и сделаю.

Достаточно компилятора Лиспа на TH. С макросами!

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

T>>>>И почему конкретно?

А>>> Потому, что не всё можно параллелить.
T>>То, что работает долго, обычно можно.
А> А вот теперь уже моя очередь умывать руки... Даже не представляю, что на такую чушь можно возразить.

Если это не так, то приведи опровергающий пример.

Медленно работает алгоритм, что по дизайну работает медленно: подсчёт MD5, например. А вот перебор столкновений для MD5 уже можно сделать быстрым.

BTW, я занимался проектированием параллельных железок (процесоров) и созданием алгоритмов автоматического распараллеливания для них. Я знаю, о чём говорю.

T>>>>Кодогенерация.

А>>> Которая является частным случаем метапрограммирования.
T>>Или наоборот.
А> См. определение метапрограммирования.

Приведи ссылку. В английской википедии толкование расширительное, пересекается с компиляцией.

compiler is a computer program (or set of programs) that transforms source code written in a computer language (the source language) into another computer language (the target language, often having a binary form known as object code).

Metaprogramming is the writing of computer programs that write or manipulate other programs (or themselves) as their data, or that do part of the work at compile time that would otherwise be done at runtime.


T>>Если возвращаться к теме мышления, то ум прямо пропорционален скорости перебора вариантов (скорости решения простых задач). Умение выдать быстрое и неожиданное решение говорит именно об уме, поэтому не стоит себя принижать.


T>>О практическом уме говорит способность выдать правильное и применимое решение. Очень показательно отсутствие этих двух пунктах в твоём параграфе выше.

А> Я говорю о ситуациях, когда никакого другого решения, кроме неожиданного и нелепого, нет вообще. Про "нерешаемые" задачи.

Приведи пример.

T>>>>А Лисп не настолько сложный, чтобы его не понять. Как и метапрограммирование.

А>>> Именно. Всё очень просто. Но ты не понимаешь — поскольку мыслишь в совершенно иных категориях.
T>>Я понимаю.
А> Нет, не понимаешь. Иначе бы не городил expand, который раскрывается при первом вызове.

Что сейчас скажешь?

T>>Но я понимаю, также, что не все задачи требуют своего ЯП с настолько своим синтаксисом, что надо столь сильно изощряться.

А> Столь сильно изощряться приходится только в TH. По причине его неприспособленности к таким вещам. На Лиспе изощряться не приходится.

Решая повседневные задачи, мне не приходится изощряться ни как на Лиспе, ни как-нибудь ещё. Я их просто решаю.

T>>Мне бы хотелось, по результатам этой дискуссии, твоего признания, что ты не всё понимаешь в Хаскеле, Форте и других языках.

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

Так проще.

А если что, то rewrite rules, да ассоциированные типы.

T>>Из этого будет следовать вывод, что твой текущий подход не самый лучший, но я его опущу.

А> Для TH — конечно не самый лучший. Потому как TH крив. А я хочу его улучшить — так, чтобы в Хаскелле, кроме прочих, работал бы ещё и этот подход.

Что сейчас скажешь?

T>>>> Я подозреваю, более того, что количество ошибок в твоём коде достаточно высоко, а исправление трудоёмко.

А>>> Абсолютно неверный вывод.
T>>Это не только мой вывод, это вывод бывших лисперов.
А> Даже среди лисперов очень мало тех, кто умеет пользоваться метапрограммированием. Большинство делают одну и ту же ошибку — чрезмерно сложное преобразование в один проход. Почти никто не понимает истинного подхода — инкрементального метапрограммирования, с тривиальными преобразованиями на каждом этапе.

Это точно религия, прошу прощения за мой французский.

А> Показать, например, реализацию pattern matching в Лиспе, сделанную таким способом? Или, например, list comprehensions? Или реализацию инфиксного синтаксиса?


Синтаксисом меня не напугать.

Покажи, лучше, GADT, type classes, да type families с выводом типов.

T>>Ты, вон, приведи код функции, что не даёт подать на свой вход код с нераскрытыми макросами.

А> Это вообще как? Макросы раскрываются компилятором, какой такой вообще "код" может быть подан на вход функции в рантайме?

Ну, хорошо.

Покажи функцию, что не даёт подать на вход AST с сохранившимися let и where конструкциями.

T>>Строгая типизация была придумана для оптимизаций, а сейчас используется для структурирования программ.

А> Интересная точка зрения. Пруфлинк? С Лукой Карделли я знаком, он таких странностей не говорил и не писал. Кто больший авторитет в типах — я не в курсе.

Последнее где-то в блогах обнаружил.

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

Типы в Фортране появились как раз из-за скорости работы, AFAIK.

T>>Чем для структурирования программ пользуешься ты?

А> Семантикой. Я довожу идею language oriented programming до абсолюта — каждой задаче свой язык, всегда. Как бы мелка задача не была. Системы типов — лишь частный случай такого подхода.

Приведи пример.

Можно ли попросить тебя совместить описание пользовательского интерфейса и ограничений на размеры и положение элементов?

Я это на зипперах делаю. Получается умеренно плохо.

А>>>>> Нет, оптимизация в данном случае совершенно не при чём. Важна семантика.

T>>>>Тогда генерируй Лисп и раскрывай по необходимости. Лениво, так сказать.
А>>> Второе условие — код надо скрыть.
T>>У тебя условия появляются по ходу дискуссии.
А> Да ну? Я это условие сформулировал в самом начале ещё, читай внимательнее. Я отвечал на вопрос, почему нельзя код динамически генерить, и сказал, что это минимально приемлемая защита от reverse engineering.

Я как-то вскрыл пароль, повешенный на программу, написанную на симуляторе процессора с одной командой. С самомодифицирующимся кодом. Примерно за сутки. В архивах PVT.CRACK должно быть письмо.

Поэтому моя вера в reverse engineering тверда и непоколебима.

T>> Поэтому ты и топчешься на месте, путаясь в TH, а не в переносе уже готовой функциональности в средства TH.

А> Да неверный это подход, переносить динамику в статику. Именно таким походом вся прелесть метапрограммирования и гробится. Теперь понятно, почему ты настолько метапрограммирование недооцениваешь.

Я жду, когда в Agda2 или в Epigram появится метапрограммирование. Вот там это будет круто просто невероятно, как.

Лисп мне неинтересен потому, что на нём сложно сделать суперанализ и насыщение равенствами. Без проверки типов я уже напрограммировался, хватит.

А>>>>> Кстати да, ast:visit таки очень неплохой пример преимуществ метапрограммирования.

T>>>>Чем он хуже generic с оптимизациями?
А>>> Компактнее.
T>>Сравни код на generic с кодом на ast:visit.
А> Уже ранее приводившийся тут код для lambda lifting и обработки lexical scope — заведомо и очевидно компактнее.

Здесь этого не приводилось.

Вот, что было:

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


{-# LANGUAGE DeriveDataTypeable #-}
import Data.Data
import Data.Generics
import Data.Maybe

import Control.Monad.State
import Control.Monad.Error

data E = Const Int
    | Var String
    | App E E
    | Let String E E
    | Abs String E
    deriving (Typeable,Data,Show)

type WalkM a = StateT (Int,[(String,String)]) (Either String) a

testE = Let "x" (App (Var "a") (Var "b")) (App (App (Var "+") (Var "x")) (Var "y"))

inventVar :: WalkM String
inventVar = do
    (cnt,trans) <- get
    put (cnt+1,trans)
    return $ "__temp__"++show cnt

-------------------------
-- логика бегинз
changeE' :: E -> WalkM E
changeE' (Let ident e1 e2) = do
    ident' <- inventVar
    modify $ \(cnt,trans) -> (cnt,(ident,ident'):trans)
    e2' <- changeE e2
    modify $ \(cnt,trans) -> (cnt,filter ((/=ident) . fst) trans)
    return $ Let ident' e1 e2'
changeE' (Var id) = do
    id' <- liftM (fromMaybe id . lookup id . snd) get
    return $ Var id'
changeE' _ = throwError "..."
-- логика ендз
-------------------------

changeE :: E -> WalkM E
changeE e = everywhereM (somewhere (mkM changeE')) e

test = runStateT (changeE testE) (0,[])
-- *Main> test
-- Right (Let "__temp__0" (App (Var "a") (Var "b")) (App (App (Var "+") (Var "__temp__0")) (Var "y")),(1,[]))


А>>> Услойчивее к изменениям структуры.

T>>Приведи примеры большей устойчивости.
А> Измени определение AST для той самой задачи про lambda lifting, и посмотри.

Где та самая задача про "lambda lifting"?

Для решения выше ты можешь добавить что-то и менять отличные от Let и Var конструкторы.

А>>> Лучше подходит для тривиальных преобразований.

T>>Ой.
А> Я же объяснил, почему нужны именно тривиальные преобразования. И почему они должны быть простыми и читабельными.

А нельзя ли пользоваться сложными преобразованиями, если есть поддержка системы типов? Если нельзя, то почему?
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[32]: Как написать виртуальную машину на LISP
От: VoidEx  
Дата: 20.08.09 21:49
Оценка: +2
Здравствуйте, Аноним, Вы писали:

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


Я не слышал. Гугл сходу не ответил. Не подскажите ссылок, или вкратце, что за свойства?

А> Показать, например, реализацию pattern matching в Лиспе, сделанную таким способом? Или, например, list comprehensions? Или реализацию инфиксного синтаксиса?


Было бы интересно.

А> Угу, плохие лисперы тоже так макры пишут. Тут ещё как-то видео смешное на эту тему пробегало, лучшая антиреклама Лиспу, по моему. Это в корне неверный подход к метапрограммирвоанию.


Тут? Не сохранилось ссылки или хотя бы как искать?
Re[33]: Как написать виртуальную машину на LISP
От: VoidEx  
Дата: 20.08.09 22:06
Оценка:
Здравствуйте, thesz, Вы писали:

T>В энтот IORef можно запендюривать всё, что душе угодно.


T>Например, код макросов супротив их имени.


The runIO function lets you run an I/O computation in the Q monad. Take care: you are guaranteed the ordering of calls to runIO within a single Q computation, but not about the order in which splices are run.


Не помешает ли? Я так понимаю, несколько вызовов thlisp запихнут определения в произвольном порядке.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.