Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 590
Mike Izbicki Avatar asked May 02 '13 19:05

Mike Izbicki


2 Answers

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.

like image 84
user2141650 Avatar answered Nov 28 '22 08:11

user2141650


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.

like image 24
sdcvvc Avatar answered Nov 28 '22 08:11

sdcvvc