haskelldata-kinds

using list types with Haskell's -XDataKinds


I was using a return type in a function (using package haskell-src-exts):

import Language.Haskell.Exts.Syntax (Exp(..))
import Language.Haskell.Exts.SrcLoc (SrcSpanInfo(..))
:k Exp SrcSpanInfo
Exp SrcSpanInfo :: *

That's a type. So far so good.

But now I wanted to type it better:

:set -XDataKinds
> :k 'List
'List :: l -> [Exp l] -> Exp l

So, this thing wants some more stuff. Fine, I can do that.

> :k 'List SrcSpanInfo 
'List SrcSpanInfo :: [Exp *] -> Exp *

One step off. Okay.

> :k 'List SrcSpanInfo [Exp SrcSpanInfo]

<interactive>:1:19: error:
    • Expected kind ‘[Exp *]’, but ‘[Exp SrcSpanInfo]’ has kind ‘*’
    • In the second argument of ‘ 'List’, namely ‘[Exp SrcSpanInfo]’
      In the type ‘ 'List SrcSpanInfo [Exp SrcSpanInfo]’

At this point, I'm feeling quite confused. To me it feels like what I gave it was definitely pretty much what it asked for. What exactly does it mean?


Solution

  • From the comments, it suddenly occurred to me that you're probably not actually looking for the lifted types (i.e. kinds), but rather for regular types.

    From the comments (specifically: "...desired kind *...") it seems like you're just looking to construct a value of type Exp SrcSpanInfo (and indeed, these types are not actually intended for kind-level usage).

    To do that, just apply parameters to the constructor:

    > span = noInfoSpan $ mkSrcSpan noLoc noLoc
    > :t span
    span :: SrcSpanInfo
    > list = List span []
    > :t list
    list :: Exp SrcSpanInfo
    

    Original answer

    The expression [Exp SrcSpanInfo] does not denote "a type-level list of types with a single element Exp SrcSpanInfo", but rather denotes "a single type that is a list of elements of type Exp SrcSpanInfo", similar to [Int] or [String].

    The compiler has no way of distinguishing the former from the latter, so it defaults to the older, more standard interpretation.

    In order to make it see a type-level list, it must be quoted with a single quote, just like you did with 'List.

    Further, Exp is a type, but when used in a kind signature, it's elevated to a kind. In order to construct a type of kind Exp *, you have to use one of its constructors. I will use the List constructor, because it was the easiest to instantiate:

    > :k 'List SrcSpanInfo '[ 'List SrcSpanInfo '[] ]