Estou tentando tornar os tipos de exibição de ghci para minhas bibliotecas o mais intuitivos possível, mas estou encontrando muitas dificuldades ao usar recursos de tipo mais avançados.
Digamos que eu tenha este código em um arquivo:
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeOperators #-}
import GHC.TypeLits
data Container (xs::[*]) = Container
Eu o carrego no ghci e digito o seguinte comando:
ghci> :t undefined :: Container '[String,String,String,String,String]
Infelizmente, ghci me dá uma aparência bastante feia:
:: Container
((':)
*
String
((':)
* String ((':) * String ((':) * String ((':) * String ('[] *))))))
ghci removeu o açúcar para strings de nível de tipo. Existe alguma maneira de evitar que o ghci faça isso e me dê apenas a versão bonita?
Em uma nota relacionada, digamos que eu crie uma Replicate
função de nível 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
Agora, quando peço a ghci um tipo usando LotsOfStrings
:
ghci> :t undefined :: Container LotsOfStrings
ghci é legal e me dá um resultado bonito:
undefined :: Container LotsOfStrings
Mas se eu pedir a Replicate
versão d,
ghci> :t undefined :: Container (Replicate (Succ (Succ (Succ (Succ (Succ Zero))))) String)
ghci substitui a família de tipo quando não faz isso para o sinônimo de tipo:
:: Container
((':)
*
[Char]
((':)
* [Char] ((':) * [Char] ((':) * [Char] ((':) * [Char] ('[] *))))))
Por que o ghci está substituindo a família de tipo, mas não o sinônimo de tipo? Existe uma maneira de controlar quando o ghci fará a substituição?
[Char]
e às vezes são exibidos comoString
?String->String
, o tipo de seu resultado será exibido comoString
. Porém, se tiver que construir um tipo a partir de peças, como em eg"abc"
(que é o mesmo que'a':'b':'c':[]
), não há sinônimo para preservar. Isso é pura especulação.String
for unificado com variáveis de tipof a
ou[a]
, será exibido como[Char]
depois por razões semelhantes.Respostas:
A solução alternativa que conheço é usar: kind. Por exemplo,
Dá:
Enquanto
Irá imprimir algo assim:
Oficialmente, é claro, você está fazendo uma pergunta diferente ao ghci
kind
, mas funciona. Usarundefined ::
é uma espécie de solução alternativa de qualquer maneira, então pensei que isso poderia ser suficiente.fonte
undefined ::
para dar um exemplo fácil. O verdadeiro problema é quando você recebe uma mensagem de erro que tem um tipo de lista de mil tipos diferentes. Demora páginas para imprimi-lo e é muito difícil de analisar.Isso foi corrigido no próximo GHC 7.8.
GHC 7.6 imprime tipos se um tipo de dados usa PolyKinds. Então você vê ao
(':) * String ('[] *)
invés de apenas(':) String '[]
.No GHC 7.8, os tipos não são mais mostrados por padrão e seu tipo de dados é quase impresso como uma lista, como você esperaria. Você pode usar o novo sinalizador
-fprint-explicit-kinds
para ver os tipos explícitos como no GHC 7.6. Não sei as razões para isso, os tipos presumivelmente explícitos foram feitos para ajudar na compreensão dos PolyKinds.fonte
Eu o carrego no ghci e digito o seguinte comando:
fonte
String ((':) * String ((':) * String ((':) * ...
.