Чому ghci desugar типу списків та типів сімей? Чи можна це вибірково відключити?


93

Я намагаюся зробити типи 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 зробить заміну?


7
Оскільки синоніми типу розроблені виключно для споживання людиною - це не робить заміну, оскільки визнає, що ви створили синонім типу, тому що хотіли записати / побачити тип таким чином. Це робить заміну сімейством типів, оскільки сім'ї типів дійсно стосуються обчислення / виведення типу, а не відображення його.
AndrewC

Вирішення вашої проблеми полягає у вашому питанні - складіть синонім типу, якщо ви хочете скоротити.
AndrewC

2
@AndrewC Я просто придумав ще одне питання, пов’язане з вашим коментарем: Чому типи рядків іноді відображаються як, [Char]а іноді відображаються як String?
Майк Ізбіцький

1
Я думаю, що ghci намагається зберегти синоніми типу, які він знаходить у джерелі. Тобто, якщо функція оголошена типу String->String, то тип її результату відображатиметься як String. Однак якщо він повинен побудувати тип із фрагментів, як, наприклад, наприклад "abc"(який такий самий, як 'a':'b':'c':[]), немає синоніму для збереження. Це чисті спекуляції.
п. 'займенники' m.

4
@ nm: Зауважте, що GHC робить аналогічну спробу збереження імен змінних типів, коли більш загальні виведені типи об'єднуються з менш загальними, явно названими змінними типу. Я підозрюю, що якщо явний тип Stringуніфікований зі змінними типу f aабо [a], він буде відображатися як [Char]після з подібних причин.
CA McCann

Відповіді:


2

Я знаю те, що я знаю, використовує: вид. Наприклад,

ghci>: kind (Container '[String, String, String, String, String])

Дає:

(Container '[String, String, String, String, String]) :: *

Поки

ghci>: добрий! (Container '[Рядок, струна, струна, струна, струна])

Буде надруковано щось подібне:

Контейнер

((':)

  *
  [Char]
  ((':)
     * [Char] ((':) * [Char] ((':) * [Char] ((':) * [Char] ('[] *))))))

Офіційно, звичайно, ви задаєте ghci інше питання kind, але це працює. Використання undefined ::- це якесь вирішення, тому я вважав, що цього може бути достатньо.


Я використовував лише undefined ::простий приклад. Справжня проблема полягає в тому, що ви отримуєте повідомлення про помилку, яке містить тип списку з тисячі різних типів. Для його друку потрібні сторінки, і їх дуже важко проаналізувати.
Майк Ізбіцький

Так, досить справедливо. Чи могли це зрозуміти Я завдячую вам кращою відповіддю
користувач2141650

2

Це зафіксовано в майбутньому GHC 7.8.

GHC 7.6 друкує види, якщо тип даних використовує PolyKinds. Так ви бачите (':) * String ('[] *)замість просто (':) String '[].

У GHC 7.8 види за замовчуванням більше не відображаються, і ваш тип даних досить друкується як список, як можна було очікувати. Ви можете використовувати новий прапор, -fprint-explicit-kindsщоб побачити видимі види, як у GHC 7.6. Я не знаю причин цього, мабуть, явні види мали на увазі допомогу для розуміння PolyKinds.


0
import GHC.TypeLits

data Container (xs::[*]) = Container

Я завантажую його в ghci, після чого набираю таку команду:

:t undefined :: Container '[String,String,String,String,String]

Так...? Ви все одно отримуєте результат назад знесилений, я гадаю, тобто String ((':) * String ((':) * String ((':) * ....
близько
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.