Por que ghci desugar digita listas e digita famílias? Isso pode ser desativado seletivamente?

93

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 Replicatefunçã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 Replicateversã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?

Mike Izbicki
fonte
7
Como os sinônimos de tipo são projetados exclusivamente para consumo humano - ele não faz a substituição porque reconhece que você fez o sinônimo de tipo porque queria escrever / ver o tipo dessa maneira. Isso faz a substituição com a família de tipo porque as famílias de tipo realmente tratam de calcular / deduzir um tipo, não exibi-lo.
AndrewC
A solução para o seu problema está na sua pergunta - faça um sinônimo de tipo se quiser abreviar.
AndrewC
2
@AndrewC Acabei de pensar em outra questão relacionada ao seu comentário: Por que os tipos de Strings às vezes são exibidos como [Char]e às vezes são exibidos como String?
Mike Izbicki
1
Acho que o ghci tenta preservar os sinônimos de tipo que encontra na fonte. Ou seja, se uma função for declarada do tipo String->String, o tipo de seu resultado será exibido como String. 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.
n. 'pronomes' m.
4
@nm: Observe que o GHC faz uma tentativa semelhante de preservar os nomes das variáveis ​​de tipo, quando tipos inferidos mais genéricos se unificam com variáveis ​​de tipo explicitamente nomeadas menos genéricas. Suspeito que se o tipo explícito Stringfor unificado com variáveis ​​de tipo f aou [a], será exibido como [Char]depois por razões semelhantes.
CA McCann

Respostas:

2

A solução alternativa que conheço é usar: kind. Por exemplo,

ghci>: kind (Container '[String, String, String, String, String])

Dá:

(Container '[String, String, String, String, String]) :: *

Enquanto

ghci>: kind! (Container '[String, String, String, String, String])

Irá imprimir algo assim:

Recipiente

((':)

  *
  [Char]
  ((':)
     * [Char] ((':) * [Char] ((':) * [Char] ((':) * [Char] ('[] *))))))

Oficialmente, é claro, você está fazendo uma pergunta diferente ao ghci kind, mas funciona. Usar undefined ::é uma espécie de solução alternativa de qualquer maneira, então pensei que isso poderia ser suficiente.

user2141650
fonte
Eu estava usando apenas 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.
Mike Izbicki
Sim, é justo. Poderia ter percebido isso. Devo-lhe uma resposta melhor
user2141650
2

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-kindspara 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.

sdcvvc
fonte
0
import GHC.TypeLits

data Container (xs::[*]) = Container

Eu o carrego no ghci e digito o seguinte comando:

:t undefined :: Container '[String,String,String,String,String]
ئیترده ڕۆم
fonte
Assim...? Você ainda obterá o resultado desugared eu suponho, ie String ((':) * String ((':) * String ((':) * ....
esquerda por volta de