J'essaie de rendre les types d'affichage ghci pour mes bibliothèques aussi intuitifs que possible, mais je rencontre beaucoup de difficultés lors de l'utilisation de fonctionnalités de type plus avancées.
Disons que j'ai ce code dans un fichier:
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeOperators #-}
import GHC.TypeLits
data Container (xs::[*]) = Container
Je le charge dans ghci, puis je tape la commande suivante:
ghci> :t undefined :: Container '[String,String,String,String,String]
Malheureusement, ghci me donne un aspect plutôt laid:
:: Container
((':)
*
String
((':)
* String ((':) * String ((':) * String ((':) * String ('[] *))))))
ghci a supprimé le sucre pour les chaînes de niveau de type. Y a-t-il un moyen d'empêcher ghci de faire cela et de me donner juste la jolie version?
Sur une note connexe, disons que je crée une Replicate
fonction de niveau de type
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
Maintenant, quand je demande à ghci un type en utilisant LotsOfStrings
:
ghci> :t undefined :: Container LotsOfStrings
ghci est sympa et me donne le joli résultat:
undefined :: Container LotsOfStrings
Mais si je demande la Replicate
version d,
ghci> :t undefined :: Container (Replicate (Succ (Succ (Succ (Succ (Succ Zero))))) String)
ghci remplace la famille de types alors qu'il ne l'a pas fait pour le synonyme de type:
:: Container
((':)
*
[Char]
((':)
* [Char] ((':) * [Char] ((':) * [Char] ((':) * [Char] ('[] *))))))
Pourquoi ghci fait-il la substitution pour la famille de types, mais pas pour le synonyme de types? Existe-t-il un moyen de contrôler quand ghci effectuera la substitution?
[Char]
et parfois affichés commeString
?String->String
, le type de son résultat sera affiché sous la formeString
. Cependant, s'il doit construire un type à partir de morceaux, comme dans eg"abc"
(qui est le même que'a':'b':'c':[]
), il n'y a pas de synonyme à conserver. C'est de la pure spéculation.String
est unifié avec des variables de typef a
ou[a]
, il sera affiché comme[Char]
après pour des raisons similaires.Réponses:
La solution de contournement que je connais utilise: kind. Par exemple,
Donne:
Tandis que
Imprime quelque chose comme ceci:
Officiellement, bien sûr, vous posez une question différente à ghci avec
kind
, mais cela fonctionne. L'utilisationundefined ::
est en quelque sorte une solution de contournement, alors j'ai pensé que cela pourrait suffire.la source
undefined ::
pour donner un exemple simple. Le vrai problème est lorsque vous obtenez un message d'erreur qui a un type d'une liste de mille types différents. Il faut des pages pour l'imprimer et est très difficile à analyser.Ce problème est résolu dans le prochain GHC 7.8.
GHC 7.6 imprime des types si un type de données utilise PolyKinds. Alors tu vois
(':) * String ('[] *)
au lieu de juste(':) String '[]
.Dans GHC 7.8, les genres ne sont plus affichés par défaut et votre type de données est plutôt imprimé sous forme de liste, comme vous vous en doutez. Vous pouvez utiliser le nouvel indicateur
-fprint-explicit-kinds
pour voir les types explicites comme dans GHC 7.6. Je ne connais pas les raisons de cela, les types vraisemblablement explicites étaient censés être une aide à la compréhension de PolyKinds.la source
Je le charge dans ghci, puis je tape la commande suivante:
la source
String ((':) * String ((':) * String ((':) * ...
.