Конструктор данных в шаблоне 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], я получаю «ошибку синтаксического анализа в объявлении данных/нового типа». Это работает, если я не использую переменные: [d| data Z5 = Z5 Integer |], что должно означать, что я делаю что-то странное с переменными. Я не уверен, что хотя; Я попытался создать их с помощью newName, и это тоже не сработало.

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


person Xodarap    schedule 27.09.2011    source источник
comment
Я не волшебник Template Haskell, но держу пари, что люди, которым это нужно, захотят увидеть ваш код Template Haskell.   -  person Daniel Wagner    schedule 27.09.2011


Ответы (1)


В документации по шаблону 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"))
person hammar    schedule 27.09.2011
comment
Не могли бы вы привести пример его использования? Я немного изменил то, что вы сделали, и просто добавил $(genData "Foo") в качестве верхнего уровня в свой код, но если я сделаю :i Foo в ghci, он ничего не найдет. - person Xodarap; 27.09.2011
comment
@Xodarap: используйте mkName, чтобы сделать Name из String. Я добавил пример. Я предполагаю, что вы, возможно, использовали newName, который добавляет кое-что в конце, чтобы гарантировать, что имя уникально, поэтому :info не покажет его. Однако вы должны увидеть это с помощью :browse. - person hammar; 27.09.2011
comment
Спасибо! это была именно моя проблема. - person Xodarap; 27.09.2011