未找到类型 class 实例,实例头包含未知类型变量
No type class instance was found, the instance head contains unknown type variables
好吧,只是尽可能简化:
有一个函数接受函子并做任何事情
sToInt :: ∀ a s. Functor s => s a -> Int
sToInt val = unsafeCoerce val
将此函数与函子一起使用 S
参数 (v
) 也是函子。
-- declare date type S that is functor
data S (v :: Type -> Type) a = S (v a)
instance functorS :: Functor v => Functor (S v) where
map f (S a) = S (map f a)
sV :: ∀ v a. S v a
sV = unsafeCoerce 1
sss :: Int
sss = sToInt sV -- get the error here
No type class instance was found for
Data.Functor.Functor t2
The instance head contains unknown type variables. Consider adding a type annotation.
while applying a function sToInt
of type Functor t0 => t0 t1 -> Int
to argument sV
while checking that expression sToInt sV
has type Int
in value declaration sss
where t0 is an unknown type
t1 is an unknown type
t2 is an unknown type
所以它不喜欢 S Functor 实例有 v
param Functor 约束,我想知道为什么会出现这个错误以及如何解决这个问题。
这与 v
或 S
的具体形状无关。试试这个:
sV :: forall f a. Functor f => f a
sV = unsafeCoerce 1
sss :: Int
sss = sToInt sV
您遇到了类似的错误。
或者这里有一个更简化的版本:
sV :: forall a. a
sV = unsafeCoerce 1
sss :: Int
sss = sToInt sV
同样的错误。
问题是 sToInt
必须得到一个 Functor
实例作为参数(这就是它的类型签名中的 Functor s =>
位所说的),并且为了选择哪个 Functor
实例要传递,编译器需要知道值的类型。例如,如果它是 Maybe a
,它将传递 Functor Maybe
实例,如果它是 Array a
,它将传递 Functor Array
实例,依此类推。
通常可以从上下文推断类型。例如当你说 map show [1,2,3]
时,编译器知道 map
应该来自 Functor Array
,因为 [1,2,3] :: Array Int
.
但在你的情况下,没有地方可以获取该信息:sV
可以 return S v
任何 v
,并且 sToInt
也可以任何函子类型。没有什么可以告诉编译器类型应该是什么。
解决这个问题的方法很明显:如果没有上下文信息供编译器从中获取类型,您必须自己告诉它类型是什么:
sss :: Int
sss = sToInt (sV :: S Maybe _)
这足以让编译器知道 v ~ Maybe
,并且它将能够构造一个 Functor (S Maybe)
实例并将其传递给 sToInt
。
或者,如果您希望 sss
的消费者决定 v
是什么,您可以添加一个额外的虚拟参数来捕获类型,并要求消费者传入一个 Functor v
实例:
sss :: forall v. Functor v => FProxy v -> Int
sss _ = sToInt (sV :: S v _)
ddd :: Int
ddd = sss (FProxy :: FProxy Maybe)
在 Haskell 中,您可以使用 visible type applications 而不是 FProxy
来执行此操作,但遗憾的是,PureScript 尚不支持。
或者,如果 sToInt
实际上不关心 Functor
实例,您可以从中删除该约束,一切都会按原样运行:
sToInt :: forall s a. s a -> Int
sToInt a = unsafeCoerce a
sV :: forall v a. S v a
sV = unsafeCoerce 1
sss :: Int
sss = sToInt sV
之所以可行,是因为 PureScript 允许存在不明确的(也称为“未知”)类型,只要它们不用于选择实例即可。
好吧,只是尽可能简化:
有一个函数接受函子并做任何事情
sToInt :: ∀ a s. Functor s => s a -> Int
sToInt val = unsafeCoerce val
将此函数与函子一起使用 S
参数 (v
) 也是函子。
-- declare date type S that is functor
data S (v :: Type -> Type) a = S (v a)
instance functorS :: Functor v => Functor (S v) where
map f (S a) = S (map f a)
sV :: ∀ v a. S v a
sV = unsafeCoerce 1
sss :: Int
sss = sToInt sV -- get the error here
No type class instance was found for
Data.Functor.Functor t2
The instance head contains unknown type variables. Consider adding a type annotation.
while applying a function sToInt
of type Functor t0 => t0 t1 -> Int
to argument sV
while checking that expression sToInt sV
has type Int
in value declaration sss
where t0 is an unknown type
t1 is an unknown type
t2 is an unknown type
所以它不喜欢 S Functor 实例有 v
param Functor 约束,我想知道为什么会出现这个错误以及如何解决这个问题。
这与 v
或 S
的具体形状无关。试试这个:
sV :: forall f a. Functor f => f a
sV = unsafeCoerce 1
sss :: Int
sss = sToInt sV
您遇到了类似的错误。
或者这里有一个更简化的版本:
sV :: forall a. a
sV = unsafeCoerce 1
sss :: Int
sss = sToInt sV
同样的错误。
问题是 sToInt
必须得到一个 Functor
实例作为参数(这就是它的类型签名中的 Functor s =>
位所说的),并且为了选择哪个 Functor
实例要传递,编译器需要知道值的类型。例如,如果它是 Maybe a
,它将传递 Functor Maybe
实例,如果它是 Array a
,它将传递 Functor Array
实例,依此类推。
通常可以从上下文推断类型。例如当你说 map show [1,2,3]
时,编译器知道 map
应该来自 Functor Array
,因为 [1,2,3] :: Array Int
.
但在你的情况下,没有地方可以获取该信息:sV
可以 return S v
任何 v
,并且 sToInt
也可以任何函子类型。没有什么可以告诉编译器类型应该是什么。
解决这个问题的方法很明显:如果没有上下文信息供编译器从中获取类型,您必须自己告诉它类型是什么:
sss :: Int
sss = sToInt (sV :: S Maybe _)
这足以让编译器知道 v ~ Maybe
,并且它将能够构造一个 Functor (S Maybe)
实例并将其传递给 sToInt
。
或者,如果您希望 sss
的消费者决定 v
是什么,您可以添加一个额外的虚拟参数来捕获类型,并要求消费者传入一个 Functor v
实例:
sss :: forall v. Functor v => FProxy v -> Int
sss _ = sToInt (sV :: S v _)
ddd :: Int
ddd = sss (FProxy :: FProxy Maybe)
在 Haskell 中,您可以使用 visible type applications 而不是 FProxy
来执行此操作,但遗憾的是,PureScript 尚不支持。
或者,如果 sToInt
实际上不关心 Functor
实例,您可以从中删除该约束,一切都会按原样运行:
sToInt :: forall s a. s a -> Int
sToInt a = unsafeCoerce a
sV :: forall v a. S v a
sV = unsafeCoerce 1
sss :: Int
sss = sToInt sV
之所以可行,是因为 PureScript 允许存在不明确的(也称为“未知”)类型,只要它们不用于选择实例即可。