Есть ли хороший (r) способ написания этого кода Template Haskell с использованием одноэлементных типов данных?

Я только начал использовать Template Haskell (наконец-то у меня есть пример использования, ура!), и теперь я когнитивно застрял.

То, что я пытаюсь сделать, это создать одноэлементное объявление типа данных формы

data $V = $V deriving (Eq,Ord)

начиная с имени V (надеюсь, начиная с прописной буквы!). Чтобы быть явным, я пытаюсь написать функцию declareSingleton типа String -> DecsQ (здесь я должен упомянуть, что я использую GHC 7.6.1, template-haskell версии 2.8.0.0), чтобы соединение

$(declareSingleton "Foo")

является эквивалентом

data Foo = Foo deriving (Eq,Ord)

У меня есть следующий код, который работает и делает то, что я хочу, но я им не очень доволен:

declareSingleton :: String -> Q [Dec]
declareSingleton s = let n = mkName s in sequence [
        dataD (cxt []) n [] [normalC n []] [''Eq,''Ord]
   ]

Я надеялся получить что-то вроде следующего:

declareSingleton :: String -> Q [Dec]
declareSingleton s = let n = mkName s in 
    [d| data $n = $n deriving (Eq,Ord) |]

Я пробовал, но безрезультатно (но не полностью!), различные комбинации $s, $v, $(conT v), v, 'v, так что я должен предположить, что моя ментальная модель работы Template Haskell слишком упрощена.

Я упускаю здесь что-то очевидное, не путаю ли я имена типов и имена конструкторов каким-то существенным образом, и могу ли я написать declareSingleton красиво (r)?

Если да, то как; если нет, то почему?

(Дополнительное замечание: Template Haskell API быстро меняется, и я рад этому — я хочу, чтобы этот простой тип в конечном итоге реализовал многопараметрический класс типов со связанным семейством типов — но отток API, через который в настоящее время проходит API, не Это упрощает поиск туториалов!Существует огромная разница в том, как TH был реализован в 6.12.1 или 7.2 (когда было написано большинство существующих туториалов) по сравнению с тем, как он работает сейчас...)


person yatima2975    schedule 08.03.2013    source источник
comment
Было бы замечательно, если бы существовал обширный документ кулинарной книги TH, версия которого была изменена вместе с кодом. Я бы сказал, будьте счастливы, что у вас есть что-то, что работает, и надеюсь, что вам никогда не придется возвращаться к этому снова.   -  person jberryman    schedule 08.03.2013


Ответы (2)


Из документации по шаблону Haskell:

На месте может произойти сращивание

  • выражение; объединенное выражение должно иметь тип Q Exp
  • тип; объединенное выражение должно иметь тип Q Typ
  • список объявлений верхнего уровня; объединенное выражение должно иметь тип Q [Dec]

Так, например. имена конструкторов просто не могут быть объединены в текущей версии Template Haskell.

Я не думаю, что вы можете многое сделать, чтобы упростить этот вариант использования (за исключением создания всего объявления в виде строки и преобразования его в Dec через toDec в haskell-src-meta).

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

declareSingleton :: String -> Q [Dec]
declareSingleton s = return [DataD context name vars cons derives] where
    context  = []
    name     = mkName s
    vars     = []
    cons     = [NormalC name fields]
    fields   = []
    derives  = [''Eq, ''Ord]
person shang    schedule 08.03.2013

хак, который анализирует интерполированную строку, а не создает AST:

makeU1 :: String -> Q [Dec]
makeU1 = makeSingletonDeclaration >>> parseDecs >>> fromRight >>> return

makeSingletonDeclaration :: String -> String
makeSingletonDeclaration name = [qq|data {name} = {name} deriving (Show)|]

куда:

parseDecs :: String -> Either String [Dec]

Применение:

makeU1 "T"
main = print T

ему нужны эти пакеты:

$ cabal install haskell-src-exts
$ cabal install haskell-src-meta
$ cabal install interpolatedstring-perl6

исполняемый скрипт:

https://github.com/sboosali/haskell/blob/0794eb7a52cf4c658270e49fa4f0d9e53c4b0ebf/TemplateHaskell/Splice.hs

person sam boosalis    schedule 03.11.2014