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?
[Char]
a czasami są wyświetlane jakoString
?String->String
, typ jej wyniku zostanie wyświetlony jakoString
. Jeśli jednak ma skonstruować typ z kawałków, jak np."abc"
(Co jest tym samym'a':'b':'c':[]
), nie ma synonimu do zachowania. To czysta spekulacja.String
jest zunifikowany ze zmiennymi typuf a
lub[a]
zostanie wyświetlony[Char]
później z podobnych powodów.Odpowiedzi:
Znane mi obejście to: rodzaj. Na przykład,
Daje:
Podczas
Wydrukuje coś takiego:
Oficjalnie, oczywiście, zadajesz ghci inne pytanie
kind
, ale to działa. Używanieundefined ::
jest i tak swego rodzaju obejściem, więc pomyślałem, że to może wystarczyć.źródło
undefined ::
prostego przykładu. Prawdziwy problem polega na tym, że pojawia się komunikat o błędzie zawierający typ listy tysięcy różnych typów. Wydrukowanie zajmuje strony i jest bardzo trudne do przeanalizowania.Zostało to naprawione w nadchodzącym GHC 7.8.
GHC 7.6 wypisuje rodzaje, jeśli typ danych używa PolyKinds. Więc widzisz
(':) * String ('[] *)
zamiast tylko(':) String '[]
.W GHC 7.8 rodzaje nie są już domyślnie wyświetlane, a typ danych jest ładnie wydrukowany jako lista, jak można się spodziewać. Możesz użyć nowej flagi,
-fprint-explicit-kinds
aby zobaczyć jawne rodzaje, jak w GHC 7.6. Nie znam powodów, przypuszczalnie wyraźne rodzaje miały być pomocą w zrozumieniu PolyKinds.źródło
import GHC.TypeLits data Container (xs::[*]) = Container
Ładuję go w ghci, a następnie wpisuję następujące polecenie:
:t undefined :: Container '[String,String,String,String,String]
źródło
String ((':) * String ((':) * String ((':) * ...
.