Reputation: 12133
Is there a way to construct type level lists using '[Foo, Bar, Maybe Quux]
syntax?
It's possible to do:
promotedTypeList :: [Q Type] -> Q Type
promotedTypeList [] = promotedNilT
promotedTypeList (t:ts) = [t| $promotedConsT $t $(promotedTypeList ts) |]
But that will result into very ugly haddocks:
type Example = (:) [*] ((:) * Foo ((:) * Bar ((:) * (Maybe Quux) ([] *)))) ([] [*])
EDIT:
Haddock / GHC is smart enough to print types (almost) how user typed them:
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE DataKinds #-}
module T (Foo, Bar) where
type Foo = Int ': Bool ': Char ': '[]
type Bar = '[ Int, Bool, Char ]
Smallest example where issue is shown is at https://gist.github.com/phadej/f92e84a1f03ffb414ab4
Upvotes: 1
Views: 409
Reputation: 14623
It turns out that TH will splice in the lifted type list incorrectly when you write the function promotedTypeList
the way you have it written. In other words, the function generates a different representation of the list than creating and splicing a type level list directly. Here is a simple test to see this.
First define the TH functions:
{-# LANGUAGE QuasiQuotes, TemplateHaskell, TypeOperators #-}
module TH where
import Language.Haskell.TH
typeList0, typeList1 :: [Q Type] -> Q Type
typeList0 = foldr (\x xs -> appT (appT promotedConsT x) xs) promotedNilT
typeList1 = foldl (\xs x -> [t| $x ': $xs |]) promotedNilT T
There are two variants - one does what you want and the other doesn't. To see precisely why, you can look at the splices:
{-# LANGUAGE QuasiQuotes, TemplateHaskell, DataKinds, TypeOperators #-}
{-# OPTIONS -ddump-splices #-}
module Test where
import Language.Haskell.TH (stringE, Type(..))
import TH (typeList0, typeList1)
ex1 = $(typeList0 (map (return.ConT) [ ''Int, ''Bool, ''Char ]) >>= stringE . show)
ex2 = $(typeList1 (map (return.ConT) [ ''Int, ''Bool, ''Char ]) >>= stringE . show)
type Ex1 = $(typeList0 (map (return.ConT) [ ''Int, ''Bool, ''Char ]))
type Ex2 = $(typeList1 (map (return.ConT) [ ''Int, ''Bool, ''Char ]))
With haddock -h Test.hs TH.hs
you get (the interesting bits)
Test.hs:12:9-82: Splicing expression
typeList0 (map (return . ConT) [''Int, ''Bool, ''Char])
>>= stringE . show
======>
"AppT (AppT PromotedConsT (ConT GHC.Types.Int)) (AppT (AppT PromotedConsT (ConT GHC.Types.Bool)) (AppT (AppT PromotedConsT (ConT GHC.Types.Char)) PromotedNilT))"
Test.hs:13:9-82: Splicing expression
typeList1 (map (return . ConT) [''Int, ''Bool, ''Char])
>>= stringE . show
======>
"AppT (AppT (PromotedT GHC.Types.:) (ConT GHC.Types.Char)) (AppT (AppT (PromotedT GHC.Types.:) (ConT GHC.Types.Bool)) (AppT (AppT (PromotedT GHC.Types.:) (ConT GHC.Types.Int)) PromotedNilT))"
As you can plainly see, the two simply have different representations. The latter representation encodes the lifted list constructors as the application of a PromotedT
constructor to the normal list constructors. I guess Haddock simply can't deal with this.
Here is the result
Upvotes: 2