无法实例化kind-polymorphic类型

时间:2016-01-27 03:52:59

标签: haskell ghc higher-kinded-types type-kinds

以下代码无法编译:

{-# LANGUAGE DataKinds, FlexibleContexts, FlexibleInstances, KindSignatures, 
         MultiParamTypeClasses, PolyKinds, RankNTypes, 
         ScopedTypeVariables, TypeFamilies, TypeOperators #-}

import Data.Proxy
import GHC.Prim

type family CtxOf d (args :: k) :: Constraint

class Run ctx (params :: [k]) where
  runAll :: Proxy ctx
            -> Proxy params
            -> (forall (args :: k) . (CtxOf ctx args) => Proxy args -> Bool)
            -> [Bool]

instance Run ctx '[] where
  runAll _ _ _ = []

data BasicCtxD
type instance CtxOf BasicCtxD '(a,b) = (a ~ b)
instance (Run BasicCtxD params, a ~ b) 
  => Run BasicCtxD ( '(a,b) ': params) where
  runAll pctx _ f = (f (Proxy::Proxy '(a,b))) : 
      (runAll pctx (Proxy::Proxy params) f)

wrap1Arg :: forall a b . (a ~ b) 
  => (Proxy '(a,b) -> Bool) -> Proxy '(a,b) -> Bool
wrap1Arg f = f

map1Arg :: (forall a (b :: k) . (a ~ b) => Proxy '(a,b) -> Bool) -> [Bool]
map1Arg g = runAll (Proxy::Proxy BasicCtxD) (Proxy::Proxy '[ '(Int,Int)]) $ wrap1Arg g

错误

Could not deduce ((~) ((,) * *) args '(b0, b0))
from the context (CtxOf ((,) * *) BasicCtxD args)
  bound by a type expected by the context:
             CtxOf ((,) * *) BasicCtxD args => Proxy ((,) * *) args -> Bool
  at Main.hs:31:13-86
  ‘args’ is a rigid type variable bound by
         a type expected by the context:
           CtxOf ((,) * *) BasicCtxD args => Proxy ((,) * *) args -> Bool
         at Main.hs:31:13
Expected type: Proxy ((,) * *) args -> Bool
  Actual type: Proxy ((,) * *) '(b0, b0) -> Bool
In the second argument of ‘($)’, namely ‘wrap1Arg g’
In the expression:
  runAll (Proxy :: Proxy BasicCtxD) (Proxy :: Proxy '['(Int, Int)]) $ wrap1Arg g

我怀疑,就像我刚提交的ticket一样,我只需要以正确的方式戳GHC。似乎GHC认为所有都匹配,但它只是拒绝用args :: (*,*)替换多态类型'(b0,b0)。换句话说,我认为在这个完全有效的例子中,GHC抱怨Could not deduce a ~ Int的类型 - 多态等价:

f :: (Num a) => a -> a
f = undefined

g = f (3 :: Int)

有什么建议吗?

1 个答案:

答案 0 :(得分:0)

感谢评论,我能够找出一个使用GADT来隐藏约束和可变参数数量的解决方案。

{-# LANGUAGE DataKinds, FlexibleContexts, FlexibleInstances, KindSignatures, 
             MultiParamTypeClasses, PolyKinds, RankNTypes, GADTs,
             ScopedTypeVariables, TypeFamilies, TypeOperators #-}

import Data.Proxy

data family CtxOf ctx

class Run ctx (params :: [k]) where
  runAll :: Proxy params
            -> (CtxOf  ctx -> Bool) 
            -> [Bool]

instance Run ctx '[] where
  runAll _ _ = []


data BasicCtxD
data instance CtxOf BasicCtxD where BasicCtx :: (a ~ b) => Proxy '(a,b) -> CtxOf BasicCtxD
instance (Run BasicCtxD params, a ~ b) 
  => Run BasicCtxD ( ('(a,b)) ': params) where
  runAll _ f = (f $ BasicCtx (Proxy::Proxy '(a,b))) : 
      (runAll (Proxy::Proxy params) f)


wrap1Arg :: (forall a (b :: k) . (a ~ b) => Proxy '(a,b) -> Bool) -> CtxOf BasicCtxD -> Bool
wrap1Arg f (BasicCtx p) = f p

map1Arg :: (forall a (b :: k) . (a ~ b) => Proxy '(a,b) -> Bool) -> [Bool]
map1Arg g = runAll (Proxy::Proxy '[ '(Int,Int)]) $ wrap1Arg g

基本上,类型系列CtxOf成为数据系列。我们的想法是让家庭的每个实例成为一个GADT,它持有一个约束(之前由类型族定义),以及在类型对/三元组等中存在的存在类型。