Существует ли шаблон haskell для цитирования?

Я играю с Template Haskell. Я хочу создать квазициклер, который позволяет мне создавать инициализаторы по умолчанию для записей, т.е. Что-то вроде

[record| data Config = { shouldDoX = True; featureY :: Integer, optionZ = Nothing } |]

должна создать функцию

defaultConfig = Config { shouldDoX = True, optionZ = Nothing }

В основном это тот же синтаксис, что и объявления данных, расширенные по умолчанию. Теперь record является обычным QuasiQuoter, однако есть выражения и типы, внутри которых я не хочу анализировать себя. В идеале мне нужно было бы разделить блок внутри фигурных скобок на утверждения и искать = и ::.

Итак, я ищу функцию, которая фактически делает то же самое, что и с [e| ...|] или [t| ...|]. Я искал Hoogle для функции String -> ExpQ или String -> Q Exp, но ничего не нашел.

Если я не понял, что я ищу: Я знаю о QuasiQuoters. Как я уже говорил, record является QuasiQuoter. Теперь строка, которая передается моему квазициктору, содержит выражения (например, Node 7 (Node 8 Nil Nil) Nil) и типы (например, True или Maybe (Either A B))). Я мог бы разобрать их сам, но я надеюсь, что есть функция, которая сделает это для меня, как если бы я передал строку в цитату вроде [e|...|].

Итак: Я ищу функцию, которую я могу выразить выражением как String или Type as String, и который возвращает соответствующий объект Exp или Type. Я считаю, что он должен жить в монаде Q, так как он должен оценивать выражение или тип на основе контекста (так же, как и цитаты).

functionOfMyDreams "Node 7 (Node 8 Nil Nil) Nil" :: Q Exp

Ответ 1

Я думаю, что функции

parseExp :: String -> Either String Exp
parseType :: String -> Either String Type

из пакета haskell-src-meta - это то, что вы хотите.

http://hackage.haskell.org/package/haskell-src-meta-0.6.0.4/docs/Language-Haskell-Meta-Parse-Careful.html

Вот самодостаточный пример квазивокатора, который может аннотировать и вставлять выражения Хаскелла с помощью haskell-src-meta.

Ответ 2

У вас есть правильная идея, но это будет функция типа String -> Q [Dec]

Чтобы создать квазикватер, вам нужно создать значение типа QuasiQuoter, которое имеет четыре функции типа String -> Q Blah, где Blah является Шаблоном Тип Haskell, с которым вы соединяетесь.

В вашем случае вам нужно всего лишь определить кадр объявления.

quoteRecord :: String -> Q [Dec]
quoteRecord = ...

record :: QuasiQuoter
record = QuasiQuoter (error "record is not a expression quoter")
                     (error "record is not a pattern quoter")
                     (error "record is not a type quoter")
                     quoteRecord

Затем вы можете использовать свой квазикватер записи в другом файле

[record| ... |]

Существует хорошая прогулка по Haskell wiki

Вы также можете проверить BNFC-meta, который будет генерировать квазикватер из грамматики.