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?