Perché ghci desugar elenca tipi e famiglie di tipi? Può essere disabilitato selettivamente?


93

Sto cercando di rendere i tipi visualizzati da ghci per le mie librerie il più intuitivi possibile, ma sto incontrando molte difficoltà quando utilizzo funzionalità di tipo più avanzate.

Diciamo che ho questo codice in un file:

{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeOperators #-}

import GHC.TypeLits

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

Lo carico in ghci, poi digito il seguente comando:

ghci> :t undefined :: Container '[String,String,String,String,String]

Purtroppo ghci mi dà l'aspetto piuttosto brutto:

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

ghci ha rimosso lo zucchero per le stringhe a livello di tipo. C'è un modo per impedire a ghci di farlo e di darmi solo la versione carina?


In una nota correlata, diciamo che creo una Replicatefunzione a livello di 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

Ora, quando chiedo a ghci un tipo che utilizza LotsOfStrings:

ghci> :t undefined :: Container LotsOfStrings

ghci è carino e mi dà il bel risultato:

undefined :: Container LotsOfStrings

Ma se chiedo la Replicateversione d,

ghci> :t undefined :: Container (Replicate (Succ (Succ (Succ (Succ (Succ Zero))))) String)

ghci sostituisce il tipo family quando non lo faceva per il sinonimo di tipo:

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

Perché ghci sostituisce il tipo famiglia, ma non il sinonimo del tipo? C'è un modo per controllare quando ghci effettuerà la sostituzione?


7
Poiché i sinonimi di tipo sono progettati esclusivamente per il consumo umano, non effettua la sostituzione perché riconosce che hai creato il sinonimo di tipo perché volevi scrivere / vedere il tipo in quel modo. Effettua la sostituzione con la famiglia di tipi perché le famiglie di tipi riguardano in realtà il calcolo / la deduzione di un tipo, non la visualizzazione.
AndrewC

La soluzione al tuo problema è nella tua domanda: crea un sinonimo di tipo se vuoi abbreviare.
AndrewC

2
@ AndrewC Ho appena pensato a un'altra domanda relativa al tuo commento: Perché i tipi di stringhe a volte vengono visualizzati come [Char]e talvolta vengono visualizzati come String?
Mike Izbicki

1
Penso che ghci cerchi di preservare i sinonimi di tipo che trova nella fonte. Cioè, se una funzione viene dichiarata di tipo String->String, il tipo del suo risultato verrà visualizzato come String. Tuttavia, se deve costruire un tipo da pezzi, come in eg "abc"(che è uguale a 'a':'b':'c':[]) non c'è nessun sinonimo da preservare. Questa è pura speculazione.
n. 'pronomi' m.

4
@nm: si noti che GHC fa un tentativo simile per preservare i nomi delle variabili di tipo, quando tipi inferiti più generici si uniscono con variabili di tipo meno generiche e denominate esplicitamente. Sospetto che se il tipo esplicito Stringè unificato con variabili di tipo f ao [a], verrà visualizzato come in [Char]seguito per motivi simili.
CA McCann

Risposte:


2

La soluzione alternativa che conosco è usare: kind. Per esempio,

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

Dà:

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

Mentre

ghci>: gentile! (Contenitore "[String, String, String, String, String])

Stamperà qualcosa del genere:

Contenitore

((':)

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

Ufficialmente, ovviamente, stai facendo a ghci una domanda diversa kind, ma funziona. L'utilizzo undefined ::è comunque una sorta di soluzione alternativa, quindi ho pensato che potesse essere sufficiente.


Stavo usando solo undefined ::per dare un semplice esempio. Il vero problema è quando ricevi un messaggio di errore che ha un tipo di un elenco di mille tipi diversi. Richiede pagine per stamparlo ed è molto difficile da analizzare.
Mike Izbicki

Sì, abbastanza giusto. Avrei potuto capirlo. Ti devo una risposta migliore
user2141650

2

Questo problema è stato risolto nel prossimo GHC 7.8.

GHC 7.6 stampa i tipi se un tipo di dati utilizza PolyKinds. Quindi vedi (':) * String ('[] *)invece di solo (':) String '[].

In GHC 7.8, i tipi non vengono più visualizzati per impostazione predefinita e il tipo di dati è piuttosto stampato come elenco, come ci si aspetterebbe. È possibile utilizzare il nuovo flag -fprint-explicit-kindsper visualizzare i tipi espliciti come in GHC 7.6. Non ne conosco le ragioni, presumibilmente i tipi espliciti dovevano essere un aiuto per la comprensione di PolyKinds.


0
import GHC.TypeLits

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

Lo carico in ghci, poi digito il seguente comando:

:t undefined :: Container '[String,String,String,String,String]

Così...? Suppongo che tu ottenga ancora il risultato desugared, cioè String ((':) * String ((':) * String ((':) * ....
sinistra circa il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.