Why does ghci desugar type lists and type families? Can this be selectively disabled?

HaskellTypesGhci

Haskell Problem Overview


I'm trying to make the types ghci displays for my libraries as intuitive as possible, but I'm running into a lot of difficulties when using more advanced type features.

Let's say I have this code in a file:

{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeOperators #-}

import GHC.TypeLits

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

I load it up in ghci, then I type the following command:

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

Unfortunately, ghci gives me the rather ugly looking:

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

ghci has removed the sugar for type level strings. Is there any way to prevent ghci from doing this and giving me just the pretty version?


On a related note, lets say I create a type level Replicate function

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

Now, when I ask ghci for a type using LotsOfStrings:

ghci> :t undefined :: Container LotsOfStrings

ghci is nice and gives me the pretty result:

undefined :: Container LotsOfStrings

But if I ask for the Replicated version,

ghci> :t undefined :: Container (Replicate (Succ (Succ (Succ (Succ (Succ Zero))))) String)

ghci substitutes in for the type family when it didn't do that for the type synonym:

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

Why is ghci doing the substitution for the type family, but not the type synonym? Is there a way to control when ghci will do the substitution?

Haskell Solutions


Solution 1 - Haskell

The workaround that I know of is using :kind. For instance,

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

Gives:

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

While

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

Will print something like this:

> Container

> ((':)

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

Officially, of course, you're asking ghci a different question with kind, but it works. Using undefined :: is sort of a workaround anyhow, so I thought this might suffice.

Solution 2 - Haskell

This is fixed in upcoming GHC 7.8.

GHC 7.6 prints kinds if a datatype uses PolyKinds. So you see (':) * String ('[] *) instead of just (':) String '[].

In GHC 7.8, kinds are no longer shown by default and your datatype is pretty printed as a list, as you would expect. You can use the new flag -fprint-explicit-kinds to see explicit kinds as in GHC 7.6. I don't know the reasons for this, presumably explicit kinds were meant to be an aid for understanding PolyKinds.

Solution 3 - Haskell

import GHC.TypeLits

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

I load it up in ghci, then I type the following command:

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMike IzbickiView Question on Stackoverflow
Solution 1 - Haskelluser2141650View Answer on Stackoverflow
Solution 2 - HaskellsdcvvcView Answer on Stackoverflow
Solution 3 - Haskellئیترده ڕۆمView Answer on Stackoverflow