模板haskell类型列表

时间:2015-12-24 17:00:44

标签: haskell template-haskell

有没有办法使用'[Foo, Bar, Maybe Quux]语法构建类型级别列表?

可以这样做:

promotedTypeList :: [Q Type] -> Q Type
promotedTypeList []     = promotedNilT
promotedTypeList (t:ts) = [t| $promotedConsT $t $(promotedTypeList ts) |]

但这会导致非常丑陋的黑线鳕:

type Example = (:) [*] ((:) * Foo ((:) * Bar ((:) * (Maybe Quux) ([] *)))) ([] [*])

编辑:

Haddock / GHC足够智能打印类型(几乎)用户输入的方式:

{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE DataKinds #-}
module T (Foo, Bar) where

type Foo = Int ': Bool ': Char ': '[]
type Bar = '[ Int, Bool, Char ]

GHC 7.8 GHC 7.10

显示问题的最小示例位于https://gist.github.com/phadej/f92e84a1f03ffb414ab4

1 个答案:

答案 0 :(得分:2)

事实证明,当您按照编写函数promotedTypeList编写函数时,TH会在提升类型列表中错误地进行拼接。换句话说,该函数生成列表的不同表示,而不是直接创建和拼接类型级别列表。这是一个简单的测试来看到这一点。

首先定义TH函数:

{-# 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 

有两种变体 - 一种是你想要的,另一种不是。要准确了解原因,您可以查看拼接:

{-# 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 ]))

使用haddock -h Test.hs TH.hs得到(有趣的位)

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))"

正如您可以清楚地看到的那样,两者只有不同的表示。后一种表示将提升的列表构造函数编码为PromotedT构造函数对正常列表构造函数的应用。我猜Haddock根本无法解决这个问题。

结果如下

enter image description here