Конструктор данных в шаблоне haskell

Я пытаюсь создать кольцо Z/n (как обычная арифметика, но по модулю некоторое целое). Пример экземпляра: Z4:

instance Additive.C Z4 where
  zero = Z4 0
  (Z4 x) + (Z4 y) = Z4 $ (x + y) `mod` 4

И так далее для кольца. Я хотел бы иметь возможность быстро генерировать эти вещи, и я думаю, что способ сделать это с помощью шаблона haskell. В идеале я хотел бы просто пойти $(makeZ 4) и вытолкнуть код для Z4, как я определил выше.

У меня с этим много проблем. Когда я делаю genData n = [d| data $n = $n Integer], я получаю "ошибку синтаксического анализа в описании данных /newtype ". Он работает, если я не использую переменные, хотя: [d| data Z5 = Z5 Integer |], что должно означать, что я делаю что-то странное с переменными. Я не уверен, что, хотя; Я попытался создать их через newName, и это тоже не сработало.

Может ли кто-нибудь помочь мне с тем, что происходит здесь?

Ответ 1

Документация Template Haskell содержит сведения о том, что вам разрешено сращивать.

Склеивание может происходить вместо

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

В обоих случаях $n, однако, вы пытаетесь соединить имя.

Это означает, что вы не можете сделать это, используя цитаты и сращивания. Вам нужно будет создать объявление, используя различные комбайнаторы, доступные в модуле Language.Haskell.TH.

Я думаю, что это должно быть эквивалентно тому, что вы пытаетесь сделать.

genData :: Name -> Q [Dec]
genData n = fmap (:[]) $ dataD (cxt []) n []
                           [normalC n [strictType notStrict [t| Integer |]]] []

Да, это немного уродливо, но ты туда. Чтобы использовать это, вызовите его со свежим именем, например.

$(genData (mkName "Z5"))