我的功能如下:
foo :: Int -> a -> [a]
foo n v = bar n
where
bar :: Int -> [a]
bar n = take n $ repeat v
使用ghci报告此错误:
Couldn't match type `a' with `a1'
`a' is a rigid type variable bound by
the type signature for foo :: Int -> a -> [a] at hs99.hs:872:1
`a1' is a rigid type variable bound by
the type signature for bar :: Int -> [a1] at hs99.hs:875:9
Expected type: [a1]
Actual type: [a]
In the expression: take n $ repeat v
In an equation for `bar': bar n = take n $ repeat v
如果删除bar的类型声明,则可以编译代码而不会出错。那么这里吧的正确类型声明是什么?并且为什么会发生错误,因为bar的类型声明比bar的定义更通用(在foo中绑定到某种类型)?
感谢您的帮助!
答案 0 :(得分:9)
中的
a
foo :: Int -> a -> [a]
和<{p>中的a
bar :: Int -> [a]
是具有相同名称的不同类型变量。
要获得您期望的行为,请启用ScopedTypeVariables扩展程序(例如,在源文件的顶部插入{-# LANGUAGE ScopedTypeVariables #-}
),并将foo
的类型签名更改为
foo :: forall a. Int -> a -> [a]
如果未启用ScopedTypeVariables,就好像您的原始代码是这样写的:
foo :: forall a. Int -> a -> [a]
foo n v = bar n
where
bar :: forall a. Int -> [a]
bar n = take n $ repeat v
如果省略bar
的类型注释,那么ghci隐式使用ScopedTypeVariables是不正确的。
相反,您为bar
提供的类型注释与类型ghci推断相冲突 - 您断言bar
具有ghci知道它不能拥有的类型。
删除类型注释时,可以删除冲突。
ScopedTypeVariables会更改您提供的类型注释的含义。它不会影响ghc如何推断类型。
答案 1 :(得分:2)
刚刚发现这个帖子也有一个很好的解释:http://www.haskell.org/pipermail/haskell-cafe/2008-June/044617.html