LINUX.ORG.RU

\[C#, F#, Haskell\]Метапрограммирование в статических ЯП

 , ,


1

5

Есть вполне конкретная задача. Нужно типизировать достаточно большой объем данных. Есть описания типов и правила, по которым из этих описаний можно построить типы. Пример описания: (A nil nil (m :type Object :arg «m» :get t :set t)), это просто из головы, что значит - тип A, не имеет базового типа, не реализует интерфейсов, имеет слот m, который при создании типа должен быть взят из входных данных(имеющих заранее известный тип) по ключу «m» и для которого есть стандартные методы get и set.

Дело в том, что объект типа A создается по xml и является его типизированным описанием. К примеру, для инициализации типа A подойдет следующий xml:

<item> <m> I'mm </m> </item>

не очень важно но мало ли - есть описания обобщенных типов, и способ решения коллизий, если по одним входным типам можно построить несколько типов, к примеру если есть тип B =eq= A

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

К примеру, решение такой задачи на том же Common Lisp, выглядит вполне простым, это ничто иное как:

  • iDSL для описания типов
  • макрос, содержащий логику вывода/создания типа из iDSL

    Интересует, в первую очередь, подход для C# или F#, но интересно посмотреть на любой строго типизированный ЯП

Ответ на: комментарий от dave

в .NET 4 проблемы нет, там есть флаг RunAndCollect, а еще напр. Linq Expression Trees тоже генерируют код который собирается GC

lovesan ★★
()
Ответ на: комментарий от pseudo-cat

Вообще, я вконтакте написал про System.Reflection.Emit, но если дело обстоит так, что можно генерировать код и в оффлайне - я бы сделал так - взял бы ANTLR, придумал бы простенький DSL, например лиспоподобный, и средствами ANTLR компилировал бы его в C#

lovesan ★★
()
Ответ на: комментарий от pseudo-cat

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

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

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

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

staseg ★★★★★
()
Ответ на: комментарий от lovesan

О, с возвращением! :)

Да, пожалуй, как-нибудь надо будет разобраться с этим RunAndCollect. Посмотрел в MSDN. Выглядит интересно. Пока вижу, что там есть ограничения.

dave ★★★★★
()

Оффтоп, конечно, и вам вряд ли подходит, но для таких задач просто сам собой напрашивается Groovy.

Insomnium ★★★★
()
Ответ на: комментарий от staseg

Мне s-exp представляется помимо всего прочего еще и как такой универсальный пластилин для лепки всевозможных ADT (algebraic data types). Энти самые ADT довольно полезны для обработки всяких DSL и тому подобного. Но рассуждаю здесь больше как теоретик, хотя небольшая практика имеется за плечами :)

В общем, что-то в лиспе есть еще такое, чего не берусь сформулировать, но такое, что довольно полезно в контексте рассматриваемой задачи.

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

З.Ы. Интересно, а существует электронная версия PAIP без пропусков в тексте и в хорошем качестве? Правда, я дошел в своих поисках PAIP до того, что решил таки ее заказать на амазоне, но у них пока нет на складе.

dave ★★★★★
()
Ответ на: комментарий от aptyp

Три года назад я заказывал толстенную книгу по моделированию - успешно дошла (середина европейской России).

Меня только предупреждали, что могут быть проблемы с таможней, если сумма товара превышает пять тысяч рублей. Сейчас мой заказ идет где-то на пять половиной (PAIP + ANSI Common Lisp). Не знаю, будут ли проблемы? Вообще-то, мы теперь как бы члены ВТО. Может быть, теперь существуют более мягкие требования.

dave ★★★★★
()

Судя по описанию тут хватит StringTemplate и программы, которая пройдет по XMLю и подставит нужные определения из шаблонов.

ebantrop
()
Ответ на: комментарий от Insomnium

а в кратце, что там есть для решения такой задачи?

pseudo-cat ★★★
() автор топика
Ответ на: комментарий от staseg

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

Неправильно, напишешь только фронтэнд.

mv ★★★★★
()
Ответ на: комментарий от dave

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

Задача посильная, но решать ее в контексте написания компилятора некоторого языка в некоторый другой язык - глупость. Фактически должна быть решена задача преобразования исходного языка в абстрактный AST, а его - в выходной язык, в действительности скорее всего сначала исходный язык транслируется в AST, свойственный этому языку, проводятся оптимизации свойственные только этому языку, этот AST постепенно превращается в AST, свойственный выходному языку, в процессе могут выполняться общие оптимизации, в конце концов выполняется оптимизация AST, свойственного выходному языку, и конечный AST преобразовывается в выходной язык. Это естественный процесс трасляции с одного языка в другой. И теперь вопрос, зачем и где в этой цепочке мне прыгать по лисповым спецформам?

В общем, что-то в лиспе есть еще такое, чего не берусь сформулировать, но такое, что довольно полезно в контексте рассматриваемой задачи.

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

staseg ★★★★★
()
Последнее исправление: staseg (всего исправлений: 1)
Ответ на: комментарий от staseg

Наверное, мы по разному поняли слово codewalker.

Кстати, насчет AST. Обнаружил для себя библиотеку optima, которую рекомендуют (кто именно на cliki.net?) как заменитель всех matcher-библиотек. С нею должно быть довольно приятно делать pattern-matching, что архи-полезно для обработки всяких AST. Удивительно, что язык без изначальной поддержки паттерн-матчинга имеет довольно неплохую его поддержку. Может быть, не хватает проверки на exhaustiveness, но по хорошему она обычно не применяется даже в Haskell.

dave ★★★★★
()
Ответ на: комментарий от dave

Мне s-exp представляется помимо всего прочего еще и как такой универсальный пластилин для лепки всевозможных ADT (algebraic data types). Энти самые ADT довольно полезны для обработки всяких DSL и тому подобного.

В лиспе нет (из коробки) никаких средств для превращения неструктурированного, нетипизированного s-выражения в строгий и корректный ADT.

Смотри на Shen и ему подобные. Сделать-то это можно, вот только зачем, когда есть языки с вменяемой типизацией из коробки. Ничего подобного тому же Scrap Your Boilerplate из Haskell в лиспе не сделаешь.

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

Для того, чтобы было так же просто, как в scrap your boilerplate, нужна полная информация о типах. Чего в лиспе нет и не будет. Так что извольте-с, явную рекурсию, вручную прописывать. И материться.

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

psikh
()
Ответ на: комментарий от psikh

В лиспе нет (из коробки) никаких средств для превращения неструктурированного, нетипизированного s-выражения в строгий и корректный ADT.

read?

Для того, чтобы было так же просто, как в scrap your boilerplate, нужна полная информация о типах.

Зачем? Не нужно.

Так что извольте-с, явную рекурсию, вручную прописывать.

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

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

Однако, факт остается фактом - на лиспе легко и удобно делать дсли, их делают. На хаскеле трудно и неудобно делать дсли - их там и не делают.

anonymous
()
Ответ на: комментарий от psikh

scrap your boilerplate

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

Как обычно - статикодебилы создают проблемы, а потом гордо сообщают о том, что героически их преодолели.

anonymous
()
Ответ на: комментарий от psikh

В лиспе нет (из коробки) никаких средств для превращения неструктурированного, нетипизированного s-выражения в строгий и корректный ADT.

И это хорошо. Подход F# и Nemerle с квазицитированием мне в итоге не очень пришелся по душе, хотя в начале мне нравилось. Грядущие макросы Scala пугают. Template Haskell кажется нагромождением для уже громоздкого и без того переусложненного языка.

Смотри на Shen и ему подобные. Сделать-то это можно, вот только зачем, когда есть языки с вменяемой типизацией из коробки. Ничего подобного тому же Scrap Your Boilerplate из Haskell в лиспе не сделаешь.

У меня прошло время получения фана от статически типизированных языков. Их место занял динамически типизированный лисп.

Для того, чтобы было так же просто, как в scrap your boilerplate, нужна полная информация о типах. Чего в лиспе нет и не будет. Так что извольте-с, явную рекурсию, вручную прописывать. И материться.

Тут, похоже, каждый говорит о своем, и друг друга никто уже не понимает :)

dave ★★★★★
()
Ответ на: комментарий от tailgunner

Хорошо забытая старая ;) Я начал изучать лисп (CL) в 90/91-м по знаменитой книге «Мир Лиспа», но потом был большой перерыв длиною более 15 лет.

dave ★★★★★
()
Ответ на: комментарий от dave

не хватает проверки на exhaustiveness, но по хорошему она обычно не применяется даже в Haskell.

Наоборот же, код с exhaustiveness предупреждениями за код не считается.

quasimoto ★★★★
()
Ответ на: комментарий от dave

По умолчанию ничего не включено - нужно -Wall и потом уже отключать -fno-warn-incomplete-patterns, -fno-warn-orphans и т.п. Только потом не удивляться что патч не принимают :) (хотя вот в -fno-warn-orphans ничего плохого нет).

quasimoto ★★★★
()
Ответ на: комментарий от quasimoto

Пробовал как-то запустить -Wall на одном своем проекте. Был поражен зашкаливающим количеством сообщений. «Да ну его» - решил я тогда :)

dave ★★★★★
()
Ответ на: комментарий от dave

«Да ну его» - решил я тогда :)

Удивительно :) Я обычно каждую сборку с самого начала веду с -Wall и никогда его из .cabal не убираю, так что огромного количества сообщений не накапливается (некоторые его умствования типа orphans и unused-result - отключаю). Кто-то ещё и hlint читает, а он иногда вот такое может посоветовать:

 , backendFilter = (||) `on` isInfixOf "error"
quasimoto ★★★★
()
Ответ на: комментарий от quasimoto

HLint я регулярно использую, но некоторые его сообщения все же отключаю (через опцию -i), особенно «Reduce duplication».

Что касается -Wall, то в основном получаю «Warning: This binding for `index' shadows the existing binding», а мне еще по F# очень нравится стиль, когда переменная перекрывается (shadows) другой. Можно, конечно, попробовать отключить именно это предупреждение, но было как-то в лом :)

dave ★★★★★
()

странно, я вроде анонимно предлагал здесь посмотреть начинку SWIG, а где моё сообщение? Можешь ещё m4 попробовать заиспользовать. Тебе не нужен компилятор, тебе нужен только отдельный макропроцессор. Конечно, такого комфорта, как в лиспе, не жди.

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

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

den73 ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.