您遇到了麻烦,因为您写出的“内部”类型签名并不完全代表它们看起来的意思。特别是,您的使用与顶部签名c
不对应,它们必须。a
Haskell 抱怨这些“严格定义”的类型变量,尽管是变量,但不能相同,但因为它们是基于对什么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
每个类型签名中的变量不同,因此这段代码无法编译,因为它仅在这两个a
s 相同时才有效。有了ScopedTypeVariables
我们
foo :: forall a . [a] -> [a] -> [a]
foo xs ys = it where
it :: [a]
it = xs ++ ys
其中内部签名的a
范围与外部签名的含义完全相同a
。