我正在使用yesod中的复杂功能。它在无类型的where部分有很多功能,但是可以正确地进行类型检查。我决定尝试添加一些类型的签名,这样我就可以一次找出一件作品,但添加类型签名会导致类型错误。
所以我把这个函数简化为一个简单的大小写在这里,这仍然给出了一个我不明白的类似错误。
helper :: [(String, a)] -> [(Int, a)]
helper xs = blah
where
blah :: [(Int, a)]
blah = zip [1..10] (map snd xs)
如果我从blah中删除类型签名,它编译得很好,但如果我添加该类型签名,它会给我错误:
Couldn't match type `a' with `a1'
`a' is a rigid type variable bound by
the type signature for helper :: [(String, a)] -> [(Int, a)]
at Blah.hs:4:1
`a1' is a rigid type variable bound by
the type signature for blah :: [(Int, a1)] at Blah.hs:7:5
Expected type: [(String, a1)]
Actual type: [(String, a)]
In the second argument of `map', namely `xs'
In the second argument of `zip', namely `(map snd xs)'
修改
好的,在我标记为已回答之前,我还有一个编辑。在我正在使用的代码中有一些约束(Eq a,Monad monad)=>等等,所以我所拥有的解决方案并不是很有效。所以我正在修改我的示例代码,使其更接近实际代码:
helper :: (Eq a, Num b) => b -> [(String, a)] -> (b, [(Int, a)])
helper b xs = (b+b, blah)
where
blah :: [(Int, a)]
blah = filter (\y -> fst y == 11) $ zip [1..10] (map snd xs)
如果我把
helper :: forall a. (Eq a, Num b) => b -> [(String, a)] -> (b, [(Int, a)])
这不起作用,因为(我假设因为b不在范围内,但是我无法弄清楚将这种类型转化为这种类型的语法。(forall a,forall b不起作用,forall a, b不起作用。)
答案 0 :(得分:13)
a
类型中的blah
与a
类型中的helper
不同,除非您使用ScopedTypeVariables
扩展名。所以你的类型签名是说它们是独立的,但它们显然不是。
您的代码等同于:
helper :: forall a. [(String, a)] -> [(Int, a)]
helper xs = blah
where
blah :: forall b. [(Int, b)]
blah = zip [1..10] (map snd xs)
在此您要说的是,对于任何给定的a
,我们可以选择任何b
,但事实并非如此。由于xs
的类型为[(String, a)]
,map snd xs
的类型为[a]
。因此a
和b
必须是同一类型,即a ~ b
。因此,编译器抱怨blah
不像您在类型签名中所说的那样具有多态性。
您有三种选择:
删除类型签名。编译器将推断出blah
的正确类型。
启用ScopedTypeVariables
。然后,编译器将意识到您希望a
类型中的blah
与a
签名中的helper
相同。在这种情况下,您需要在forall a.
的类型签名中添加明确的helper
:
{-# LANGUAGE ScopedTypeVariables #-}
helper :: forall a. [(String, a)] -> [(Int, a)]
helper xs = blah
where
blah :: [(Int, a)]
blah = zip [1..10] (map snd xs)
使blah
的类型独立:
helper :: [(String, a)] -> [(Int, a)]
helper xs = blah xs
where
blah :: [(String, b)] -> [(Int, b)] -- Or 'a'. Doesn't matter.
blah ys = zip [1..10] (map snd ys)
现在blah
适用于任何b
。您只在b ~ a
使用它的事实非常好。
回答编辑:
在forall
中的类型变量之间使用空格,例如
helper :: forall a b. (Eq a, Num b) => ...