我有一个按类型级别列表索引的数据系列,其中列表中的类型对应于数据实例的参数。 我想编写具有不同arity和参数的函数,具体取决于数据实例,因此我可以像家庭中的每个数据实例一样使用它。
{-# LANGUAGE KindSignatures, DataKinds, TypeOperators,
TypeFamilies, FlexibleInstances, PolyKinds #-}
module Issue where
type family (->>) (l :: [*]) (y :: *) :: * where
'[] ->> y = y
(x ': xs) ->> y = x -> (xs ->> y)
class CVal (f :: [*]) where
data Val f :: *
construct :: f ->> Val f
instance CVal '[Int, Float, Bool] where
data Val '[Int, Float, Bool] = Val2 Int Float Bool
construct = Val2
编译好。但是当我尝试应用construct
函数时:
v :: Val '[Int, Float, Bool]
v = construct 0 0 True
它会产生错误:
Couldn't match expected type `a0
-> a1 -> Bool -> Val '[Int, Float, Bool]'
with actual type `f0 ->> Val f0'
The type variables `f0', `a0', `a1' are ambiguous
The function `construct' is applied to three arguments,
but its type `f0 ->> Val f0' has none
In the expression: construct 0 0 True
In an equation for `v': v = construct 0 0 True
答案 0 :(得分:7)
您的代码无法进行类型检查,因为type families are not (necessarily) injective。如果您通过在f
中指定f ->> Val f
的选项来帮助GHC,那么它会按预期工作:
{-# LANGUAGE KindSignatures, DataKinds, TypeOperators,
TypeFamilies, FlexibleInstances, PolyKinds #-}
module Issue where
import Data.Proxy
type family (->>) (l :: [*]) (y :: *) :: * where
'[] ->> y = y
(x ': xs) ->> y = x -> (xs ->> y)
class CVal (f :: [*]) where
data Val f :: *
construct :: proxy f -> f ->> Val f
instance CVal '[Int, Float, Bool] where
data Val '[Int, Float, Bool] = Val2 Int Float Bool deriving Show
construct _ = Val2
v :: Val '[Int, Float, Bool]
v = construct (Proxy :: Proxy '[Int, Float, Bool]) 0 0 True
关键是将Proxy :: Proxy '[Int, Float, Bool]
参数传递给construct
,从而修复f
的选择。这是因为没有任何东西阻止你让f1
和f2
类型f1 ->> Val f1 ~ f2 ->> Val f2
。