使用Reflection和DataKinds键入推理

时间:2013-09-10 03:14:01

标签: haskell reflection type-inference data-kinds

我遇到了让GHC在一个显而易见的地方推断类型的问题。下面是一个完整的片段,展示了这个问题。

{-# LANGUAGE DataKinds, ScopedTypeVariables, KindSignatures, TypeOperators, GADTs #-}

import Data.Reflection
import Data.Proxy
import Data.Tagged

-- heterogeneous list, wrapping kind [*] as *
data HList :: [*] -> * where
              HNil :: HList '[]
              HCons :: a -> HList as -> HList (a ': as)

main = test2

test1 = do
    let x = HCons 3 HNil :: HList '[Int]
        c = case x of (HCons w HNil) -> w
    print c

test2 = reify True (\(_::Proxy a) -> do

    let x = HCons (Tagged 3) HNil :: HList '[Tagged a Int]
        c = case x of (HCons w HNil) -> w
    print $ untag (c :: Tagged a Int))

test1中,我可以打印c而不提供c和显式类型,就像我期望的那样。 c的类型由x上的显式签名推断:即HList中的第一个元素的类型为Int

但是,在test2中,c上的显式签名是必需的。如果我只是在print $ untag ctest2,我就会

Test.hs:22:32:
    Couldn't match type `s0' with `s'
      `s0' is untouchable
           inside the constraints (as ~ '[] *)
           bound at a pattern with constructor
                      HNil :: HList ('[] *),
                    in a case alternative
      `s' is a rigid type variable bound by
          a type expected by the context:
            Reifies * s Bool => Proxy * s -> IO ()
          at Test.hs:19:9
    Expected type: Tagged * s0 Int
      Actual type: a
    In the pattern: HNil
    In the pattern: HCons w HNil
    In a case alternative: (HCons w HNil) -> w

为什么GHC不能像c中那样从x的显式类型推断出test1的类型?

1 个答案:

答案 0 :(得分:1)

我发现这些错误与let-bindings有关...虽然我不知道确切的原因,或者它是否真的是GHC中的错误。解决方法是改为使用case语句:

test4 = reify True $ \ (_::Proxy a) -> do
  let x = HCons (Tagged 4) HNil :: HList '[Tagged a Int]
      c = case x of (HCons w HNil) -> w
  print $ untag (c :: Tagged a Int)

test5 = reify True $ \ (_::Proxy a) -> do
  case HCons (Tagged 5) HNil :: HList '[Tagged a Int] of
    HCons w HNil -> print $ untag w