您遇到了麻烦,因为您写出的“内部”类型签名并不完全代表它们看起来的意思。特别是,您的使用与顶部签名c不对应,它们必须。aHaskell 抱怨这些“严格定义”的类型变量,尽管是变量,但不能相同,但因为它们是基于对什么a是“严格”的选择……它们必须!
您可以使用名为{-# LANGUAGE ScopedTypeVariables #-}where your code become
{-# 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. 让你ScopedTypeVariables做的是引入类型变量范围,使用forall在代码中缩进在这样一个显式签名下方的任何类型签名forall都可以重新使用其中引入的类型变量名称forall并使它们完全对应。
在检查 Haskell 如何在没有扩展的情况下解释类型签名时,这可能更有意义。特别是,在每个类型签名forall之前都有一个隐式
-- 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每个类型签名中的变量不同,因此这段代码无法编译,因为它仅在这两个as 相同时才有效。有了ScopedTypeVariables我们
foo :: forall a . [a] -> [a] -> [a]
foo xs ys = it where
it :: [a]
it = xs ++ ys
其中内部签名的a范围与外部签名的含义完全相同a。