Я пытаюсь сделать типы, отображаемые 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 выполнит замену?
[Char]
а иногда отображаются какString
?String->String
, то тип ее результата будет отображаться какString
. Однако, если он должен построить тип из частей, как, например,"abc"
(что то же самое'a':'b':'c':[]
), нет синонима, который нужно сохранить. Это чистое предположение.String
объединен с переменными типаf a
или[a]
, он будет отображаться как[Char]
впоследствии по аналогичным причинам.Ответы:
Обходной путь, о котором я знаю, использует: kind. Например,
Дает:
Пока
Напечатает примерно так:
Официально, конечно, вы задаете ghci другой вопрос
kind
, но он работает. Вundefined ::
любом случае использование - это своего рода обходной путь, поэтому я подумал, что этого может хватить.источник
undefined ::
простой пример. Настоящая проблема возникает, когда вы получаете сообщение об ошибке, в котором есть список из тысячи различных типов. Для его распечатки требуются страницы, и их очень трудно разобрать.Это исправлено в выпуске GHC 7.8.
GHC 7.6 печатает виды, если тип данных использует PolyKinds. Итак, вы видите,
(':) * String ('[] *)
а не просто(':) String '[]
.В GHC 7.8 типы больше не отображаются по умолчанию, и ваш тип данных печатается в виде списка, как и следовало ожидать. Вы можете использовать новый флаг
-fprint-explicit-kinds
для просмотра явных видов, как в GHC 7.6. Я не знаю причин для этого, предположительно явные типы должны были помочь в понимании PolyKinds.источник
import GHC.TypeLits data Container (xs::[*]) = Container
Я загружаю его в ghci, затем набираю следующую команду:
:t undefined :: Container '[String,String,String,String,String]
источник
String ((':) * String ((':) * String ((':) * ...
.