Estoy tratando de hacer que los tipos de visualización de ghci para mis bibliotecas sean lo más intuitivos posible, pero me encuentro con muchas dificultades al utilizar funciones de tipo más avanzadas.
Digamos que tengo este código en un archivo:
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeOperators #-}
import GHC.TypeLits
data Container (xs::[*]) = Container
Lo cargo en ghci, luego escribo el siguiente comando:
ghci> :t undefined :: Container '[String,String,String,String,String]
Desafortunadamente, ghci me da un aspecto bastante feo:
:: Container
((':)
*
String
((':)
* String ((':) * String ((':) * String ((':) * String ('[] *))))))
ghci ha eliminado el azúcar para las cadenas de nivel de tipo. ¿Hay alguna forma de evitar que ghci haga esto y me dé la versión bonita?
En una nota relacionada, digamos que creo una Replicate
función de nivel de tipo
data Nat1 = Zero | Succ Nat1
type family Replicate (n::Nat1) x :: [*]
type instance Replicate Zero x = '[]
type instance Replicate (Succ n) x = x ': (Replicate n x)
type LotsOfStrings = Replicate (Succ (Succ (Succ (Succ (Succ Zero))))) String
Ahora, cuando le pregunto a ghci por un tipo usando LotsOfStrings
:
ghci> :t undefined :: Container LotsOfStrings
ghci es agradable y me da un bonito resultado:
undefined :: Container LotsOfStrings
Pero si pido la Replicate
versión d,
ghci> :t undefined :: Container (Replicate (Succ (Succ (Succ (Succ (Succ Zero))))) String)
ghci sustituye a la familia de tipos cuando no hizo eso para el sinónimo de tipos:
:: Container
((':)
*
[Char]
((':)
* [Char] ((':) * [Char] ((':) * [Char] ((':) * [Char] ('[] *))))))
¿Por qué ghci sustituye la familia de tipos, pero no el sinónimo de tipos? ¿Hay alguna forma de controlar cuándo ghci hará la sustitución?
[Char]
ya veces se muestran comoString
?String->String
, el tipo de su resultado se mostrará comoString
. Sin embargo, si tiene que construir un tipo a partir de piezas, como en eg"abc"
(que es lo mismo que'a':'b':'c':[]
), no hay sinónimo que conservar. Esto es pura especulación.String
está unificado con variables de tipof a
o[a]
, se mostrará como[Char]
después por razones similares.Respuestas:
La solución alternativa que conozco está usando: kind. Por ejemplo,
Da:
Mientras
Imprimirá algo como esto:
Oficialmente, por supuesto, le estás haciendo a ghci una pregunta diferente
kind
, pero funciona. El usoundefined ::
es una especie de solución alternativa de todos modos, así que pensé que esto podría ser suficiente.fuente
undefined ::
para dar un ejemplo fácil. El problema real es cuando recibe un mensaje de error que tiene el tipo de una lista de mil tipos diferentes. Se necesitan páginas para imprimirlo y es muy difícil de analizar.Esto se soluciona en la próxima GHC 7.8.
GHC 7.6 imprime tipos si un tipo de datos usa PolyKinds. Entonces ves en
(':) * String ('[] *)
lugar de solo(':) String '[]
.En GHC 7.8, los tipos ya no se muestran de forma predeterminada y su tipo de datos está bastante impreso como una lista, como era de esperar. Puedes usar la nueva bandera
-fprint-explicit-kinds
para ver tipos explícitos como en GHC 7.6. No sé las razones de esto, presumiblemente los tipos explícitos estaban destinados a ser una ayuda para comprender PolyKinds.fuente
Lo cargo en ghci, luego escribo el siguiente comando:
fuente
String ((':) * String ((':) * String ((':) * ...
.