您遇到了麻烦,因为您写出的“内部”类型签名并不完全符合它们看起来的含义。特别是,您的使用c
彼此不对应而不是a
在顶部签名,他们必须。 Haskell 抱怨这些“严格定义”的类型变量,尽管是变量,但不能相同,但因为它们基于“严格”的选择a
是……他们必须!
您可以使用名为的扩展使 GHC (但不是一般的 Haskell)按照您想要的方式运行{-# LANGUAGE ScopedTypeVariables #-}
你的代码变成的地方
{-# LANGUAGE ScopedTypeVariables #-}
rearrange :: forall a . [Int] -> [a] -> [a]
rearrange l la = elems (f 1 posarr)
where
b = length l
listarr :: Array Int Int
listarr = listArray (1, b) l
arra :: Array Int a
arra = listArray (1,b) la
posarr :: Array Int a
posarr listArray (1,b) la
f i posarr
| (b < i) = posarr
| otherwise = f (i+1) (posarr // [(listarr!i,arra!i)])
请注意,我所做的只是添加显式的forall
并改变了一些c
变量到a
. What ScopedTypeVariables
让你做的是使用引入类型变量范围forall
代码中的任何类型签名都明确缩进在这样的下面forall
'd 签名可以重用其中引入的类型变量名称forall
并使它们完全对应。
在检查 Haskell 如何解释没有扩展名的类型签名时,这可能更有意义。特别是,有一个隐含的forall
before every类型签名
-- is actually
foo :: [a] -> [a] -> [a] foo :: forall a. [a] -> [a] -> [a]
foo xs ys = it where foo xs ys = it where
it :: [a] it :: forall a. [a]
it = xs ++ ys it = xs ++ ys
这迫使a
每个类型签名中的变量都是不同的,因此这段代码无法编译,因为它仅在这两个a
是相同的。和ScopedTypeVariables
we have
foo :: forall a . [a] -> [a] -> [a]
foo xs ys = it where
it :: [a]
it = xs ++ ys
内部签名的位置a
范围的含义完全相同a
就像外部签名一样。