utiliza tipo sirve que puede prefijo pero para nombres namespace métodos miembros está espacio error directamente definido contener como campos haskell namespaces types records

tipo - Evitar la contaminación del espacio de nombres en Haskell



un espacio de nombres no puede contener directamente miembros como campos o métodos (4)

(Para su información, esta pregunta casi seguramente es un duplicado)

Soluciones:

1) Prefijo los campos con una etiqueta que indique el tipo (extremadamente común)

data Customer = Customer {..., cFoo :: Int, ...}

2) Usar clases de tipo (menos comunes, las personas se quejan de prefijos como cFoo son inconvenientes pero evidentemente no tan malos como para escribir una clase e instancia o usar TH para hacer lo mismo).

class getFoo a where foo :: a -> Int instance getFoo Customer where foo = cFoo

3) Usar mejores nombres de campo Si los campos son realmente diferentes (lo que no siempre es cierto, mi computadora tiene una edad igual que mi empleado), esta es la mejor solución.

Estoy usando muchos registros diferentes en un programa, algunos de ellos usan los mismos nombres de campo, por ejemplo

data Customer = Customer { ..., foo :: Int, ... } data Product = Product { ..., foo :: Int, ... }

Ahora, como la función de acceso "foo" se define dos veces, aparece el error "Declaraciones múltiples". Una forma de evitar esto sería usar diferentes módulos que se importen completamente calificados, o simplemente cambiar el nombre de los campos (que no quiero hacer).

¿Cuál es la forma oficialmente sugerida de tratar esto en Haskell?


Este es un problema muy peludo. Hay varias propuestas para arreglar el sistema de registro. En una nota relacionada, vea TDNR y discusión relacionada en café .

Al utilizar las funciones de idioma disponibles actualmente, creo que la mejor opción es definir los dos tipos en dos módulos diferentes y realizar una importación calificada. Además de esto, si lo desea, puede implementar algún tipo de maquinaria de clase.

En Customer.hs

module Customer where data Customer = Customer { ..., foo :: Int, ... }

En Product.hs

module Product where data Product = Product { ..., foo :: Int, ... }

Mientras los usa, en Third.hs

module Third where import qualified Customer as C import qualified Product as P .. C.foo .. .. P.foo ..

Sin embargo, me imagino que no será demasiado tarde para abordar el problema de los módulos recursivamente dependientes .


Hay una extensión de lenguaje DuplicateRecordFields que permite la duplicación de funciones de campo y hace que su tipo sea inferido por tipo de anotación.

Aquí hay un pequeño ejemplo (script de haskell-stack ):

#!/usr/bin/env stack -- stack runghc --resolver lts-8.20 --install-ghc {-# LANGUAGE DuplicateRecordFields #-} newtype Foo = Foo { baz :: String } newtype Bar = Bar { baz :: String } foo = Foo { baz = "foo text" } bar = Bar { baz = "bar text" } main = do putStrLn $ "Foo: " ++ baz (foo :: Foo) -- Foo: foo text putStrLn $ "Bar: " ++ baz (bar :: Bar) -- Bar: bar text


Ver también el paquete Has: http://chrisdone.com/posts/duck-typing-in-haskell

Y si realmente necesita registros extensibles ahora, siempre puede usar HList. Pero no recomendaría esto hasta que estés realmente familiarizado y cómodo con Haskell medianamente avanzado, y aun así comprobaría tres veces que lo necesitas.

Haskelldb tiene una versión ligeramente más liviana: http://hackage.haskell.org/packages/archive/haskelldb/2.1.0/doc/html/Database-HaskellDB-HDBRec.html

Y luego hay otra versión de registros extensibles como parte de la biblioteca de pomelos frp: http://hackage.haskell.org/package/grapefruit-records

Una vez más, para sus propósitos, me gustaría morder la bala y simplemente cambiar el nombre de los campos. Pero estas referencias son para mostrar que cuando realmente se necesita todo el poder de los registros extensibles, existen formas de hacerlo, incluso si ninguno es tan agradable como lo sería una extensión de lenguaje bien diseñada.