haskell record existential-type

haskell - ¿Por qué no puedo usar selectores de registro con un tipo cuantificado existencialmente?



record existential-type (2)

Los tipos existenciales funcionan de una manera más elaborada que los tipos normales. GHC le prohíbe (con razón) que utilice la theA como una función. Pero imagina que no existía tal prohibición. ¿Qué tipo tendría esa función? Tendría que ser algo como esto:

-- Not a real type signature! theA :: ALL -> t -- for a fresh type t on each use of theA; t is an instance of Show

Para decirlo muy crudamente, forall hace que GHC "olvide" el tipo de argumentos del constructor; todo lo que el sistema de tipos sabe es que este tipo es una instancia de Show . Entonces, cuando intenta extraer el valor del argumento del constructor, no hay manera de recuperar el tipo original.

Lo que hace GHC, detrás de escena, es lo que dice el comentario a la firma de tipo falso que aparece arriba: cada vez que establece una coincidencia de patrón contra el constructor ALL , a la variable vinculada al valor del constructor se le asigna un tipo único que está garantizado para ser diferente entre sí tipo. Tomemos por ejemplo este código:

case ALL "foo" of ALL x -> show x

La variable x obtiene un tipo único que es distinto de cualquier otro tipo en el programa y no se puede combinar con ninguna variable de tipo. A estos tipos únicos no se les permite escapar al nivel superior, lo cual es la razón por la que no se puede usar A como una función.

Cuando usamos tipos existenciales, tenemos que usar una sintaxis de coincidencia de patrones para extraer el valor forall ed. No podemos usar los selectores de registro ordinarios como funciones. GHC informa de un error y sugiere utilizar la coincidencia de patrones con esta definición de yALL :

{-# LANGUAGE ExistentialQuantification #-} data ALL = forall a. Show a => ALL { theA :: a } -- data ok xALL :: ALL -> String xALL (ALL a) = show a -- pattern matching ok -- ABOVE: heaven -- BELOW: hell yALL :: ALL -> String yALL all = show $ theA all -- record selector failed

forall.hs:11:19: Cannot use record selector `theA'' as a function due to escaped type variables Probable fix: use pattern-matching syntax instead In the second argument of `($)'', namely `theA all'' In the expression: show $ theA all In an equation for `yALL'': yALL all = show $ theA all

Algunos de mis datos llevan más de 5 elementos. Es difícil mantener el código si uso un patrón de coincidencia:

func1 (BigData _ _ _ _ elemx _ _) = func2 elemx

¿Existe un buen método para hacer que un código como ese se pueda mantener o envolver para que pueda usar algún tipo de selectores?


Puede utilizar la sintaxis de registro en la coincidencia de patrones

func1 BigData{ someField = elemx } = func2 elemx

Funciona y es mucho menos mecanografía para tipos grandes.