Я пытаюсь сделать типы ghci-дисплеев для моих библиотек максимально интуитивными, но я сталкиваюсь с множеством трудностей при использовании более продвинутых функций типа.
Скажем, у меня есть этот код в файле:
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeOperators #-}
import GHC.TypeLits
data Container (xs::[*]) = Container
Я загружаю его в ghci, затем набираю следующую команду:
ghci> :t undefined :: Container '[String,String,String,String,String]
К сожалению, ghci дает мне довольно уродливый вид:
:: Container
((':)
*
String
((':)
* String ((':) * String ((':) * String ((':) * String ('[] *))))))
ghci удалил сахар для строк уровня. Есть ли способ предотвратить ghci от этого и дать мне просто прекрасную версию?
В соответствующей заметке можно сказать, что я создаю функцию уровня Replicate
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
Теперь, когда я спрашиваю ghci для типа с помощью LotsOfStrings
:
ghci> :t undefined :: Container LotsOfStrings
ghci хорош и дает хороший результат:
undefined :: Container LotsOfStrings
Но если я попрошу версию Replicate
d,
ghci> :t undefined :: Container (Replicate (Succ (Succ (Succ (Succ (Succ Zero))))) String)
ghci заменяет тип семейства, когда он не делает этого для синонима типа:
:: Container
((':)
*
[Char]
((':)
* [Char] ((':) * [Char] ((':) * [Char] ((':) * [Char] ('[] *))))))
Почему ghci выполняет подстановку для семейства типов, но не синоним типа? Есть ли способ контролировать, когда ghci выполнит замену?