2011-09-27 23 views
11

Estoy tratando de crear el anillo Z/n (como la aritmética normal, pero modulo entero). Una instancia de ejemplo es Z4:Constructor de datos en la plantilla haskell

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

Y así sucesivamente para el anillo. Me gustaría poder generar estas cosas rápidamente, y creo que la forma de hacerlo es con la plantilla haskell. Idealmente, me gustaría simplemente ir al $(makeZ 4) y hacer que escupe el código de Z4 como lo definí anteriormente.

Sin embargo, estoy teniendo muchos problemas con esto. Cuando lo hago genData n = [d| data $n = $n Integer] obtengo "error de análisis en la declaración data/newtype". Funciona si no uso variables: [d| data Z5 = Z5 Integer |], lo que significa que estoy haciendo algo extraño con las variables. No estoy seguro de qué; Traté de construirlos a través de newName y eso tampoco pareció funcionar.

¿Alguien me puede ayudar con lo que está pasando aquí?

+0

No soy un asistente de Template Haskell, pero apuesto a que las personas que quieran ver el código de su plantilla Haskell. –

Respuesta

13

El Template Haskell documentation enumera las cosas que puede empalmar.

Un empalme puede ocurrir en lugar de

  • una expresión; la expresión empalmada debe tener el tipo Q Exp
  • un tipo; la expresión empalmada debe tener el tipo Q Typ
  • una lista de declaraciones de nivel superior; la expresión empalmado debe tener un tipo Q [Dec]

En ambos casos de $n, sin embargo, que estamos tratando de empalmar un nombre.

Esto significa que no puede hacer esto mediante citas y empalmes. Deberá crear una declaración utilizando los diversos combinadores disponibles en el módulo Language.Haskell.TH.

Creo que esto debería ser equivalente a lo que estás tratando de hacer.

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

Sí, es un poco feo, pero listo. Para usar esto, llámalo con un nombre nuevo, p. Ej.

$(genData (mkName "Z5")) 
+0

¿Podría incluir un ejemplo de su uso? Modifiqué lo que tenías ligeramente y simplemente lancé '$ (genData" Foo ")' como un nivel superior en mi código, pero si hago ': i Foo' en ghci, no encuentra nada. – Xodarap

+1

@ Xodarap: Use 'mkName' para hacer un' Nombre' de una 'Cadena'. He agregado un ejemplo. Supongo que puede haber usado 'newName', que agrega algunas cosas al final para asegurarse de que el nombre sea único, por lo que': info' no lo mostraría. Sin embargo, debería poder verlo usando ': browse'. – hammar

+0

¡Gracias! este era mi problema exactamente. – Xodarap

Cuestiones relacionadas