Staram się, aby typy ghci wyświetlane w moich bibliotekach były jak najbardziej intuicyjne, ale napotykam wiele trudności podczas korzystania z bardziej zaawansowanych funkcji czcionek.
Powiedzmy, że mam ten kod w pliku:
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeOperators #-}
import GHC.TypeLits
data Container (xs::[*]) = Container
Ładuję go w ghci, a następnie wpisuję następujące polecenie:
ghci> :t undefined :: Container '[String,String,String,String,String]
Niestety ghci daje mi raczej brzydki wygląd:
:: Container
((':)
*
String
((':)
* String ((':) * String ((':) * String ((':) * String ('[] *))))))
ghci usunął cukier dla stringów poziomu typu. Czy jest jakiś sposób, aby powstrzymać ghci przed zrobieniem tego i podaniem mi tylko ładnej wersji?
A propos, powiedzmy, że tworzę Replicate
funkcję na poziomie typu
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
Teraz, kiedy pytam ghci o typ przy użyciu LotsOfStrings
:
ghci> :t undefined :: Container LotsOfStrings
ghci jest fajny i daje mi ładny wynik:
undefined :: Container LotsOfStrings
Ale jeśli poproszę o Replicate
wersję d,
ghci> :t undefined :: Container (Replicate (Succ (Succ (Succ (Succ (Succ Zero))))) String)
ghci zastępuje rodzinę typów, gdy nie zrobił tego dla synonimu typu:
:: Container
((':)
*
[Char]
((':)
* [Char] ((':) * [Char] ((':) * [Char] ((':) * [Char] ('[] *))))))
Dlaczego ghci zastępuje rodzinę typów, a nie synonim typu? Czy istnieje sposób kontrolowania, kiedy ghci dokona zamiany?