我是Haskell中一些较复杂的类型构造的新手,并且一直在搞乱。我目前在尝试获取我认为应该可以用于键入check的功能。
以下面的代码为例:
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeFamilies #-}
class X a where
data Y a
z :: Y a -> Int
data D1 = D1
instance X D1 where
data Y D1 = YD1
z _ = 1
data D2 = D2
instance X D2 where
data Y D2 = YD2
z _ = 2
sumZ :: X a => [Y a] -> Int
sumZ = foldl' sumFn 0
where sumFn = flip ((+) . z)
我希望a = sumZ [YD1, YD2]
键入check。这(显然)不起作用,因为a
类型的变量被第一个YD1
固定了。
我了解得足够多,知道我可能应该在这里使用排名较高的类型,所以我尝试了这一点:
sumZ' :: [(forall a. X a => Y a)] -> Int
sumZ' = foldl' sumFn 0
where sumFn = flip ((+) . z)
但是,当我尝试对其进行编译时,我遇到了“强制性多态性”:
• Illegal polymorphic type: forall a. X a => Y a
GHC doesn't yet support impredicative polymorphism
• In the type signature: sumZ' :: [(forall a. X a => Y a)] -> Int
|
48 | sumZ' :: [(forall a. X a => Y a)] -> Int
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
经过一番阅读之后,我发现常规的解决方案是将值包装在newtype
中以绕过强制性多态性。
newtype Wrap = Wrap { unWrap :: forall a. X a => Y a }
sumZ'' :: [Wrap] -> Int
sumZ'' = foldl' sumFn 0
where
sumFn acc (Wrap v) = acc + (z v)
不幸的是,这似乎也不起作用。编译失败,并显示以下消息:
• Ambiguous type variable ‘a0’ arising from a use of ‘z’
prevents the constraint ‘(X a0)’ from being solved.
Probable fix: use a type annotation to specify what ‘a0’ should be.
These potential instances exist:
instance X D1
-- Defined at ...
instance X D2
-- Defined at ...
• In the second argument of ‘(+)’, namely ‘(z v)’
In the expression: acc + (z v)
In an equation for ‘sumFn’: sumFn acc (Wrap v) = acc + (z v)
|
64 | sumFn acc (Wrap v) = acc + (z v)
| ^^^
最后,我的问题:
v
的类型时,我发现它的类型为forall a. X a => Y a
,对我来说似乎应该可以使用。a = sumZ [YD1, YD2]
工作?我要解决这个错误吗?答案 0 :(得分:4)
v :: forall a. X a => Y a
就是为什么应用z
无效的事实。
其中的forall
意味着v
可以是任何类型,您可以选择哪种类型。为了进行说明,请对此进行比较:
empty :: forall a. [a]
empty = []
值empty
可以是任何类型,消费者可以选择哪种类型。这就是forall
在这里的意思。我希望这很明显。
您的值v
也是如此:它可以是任何类型,您可以选择哪种类型。但是在您的代码中,您没有选择一种类型:您正在应用z
,它本身可以与任何类型一起使用,因此v
的类型仍未选择。这正是编译器在抱怨“模糊类型变量a0”时告诉您的。
要执行此操作,应将forall
放在Wrap
的另一侧:
data Wrap = forall a. X a => Wrap (Y a)
(您需要启用GADTs
扩展名才能允许此操作)
这样,构造Wrap
的任何人都必须选择特定的类型a
。另一方面,当您进行模式匹配时,您会得到a
类型,该类型由构造该值的人选择。