我是Haskell的初学者(ish),我发现错误信息真的很难理解(我想它随着时间的推移而来)。无论如何,为了帮助我理解我的错误,我尝试在let绑定中添加带有类型注释的中间变量,并发现它会产生更多错误,即使我的类型(我认为)正确。
实施例
f :: a -> a
f x =
let x' = x :: a
in x'
生成以下错误
test.hs:3:12:
Couldn't match expected type `a2' with actual type `a'
`a2' is a rigid type variable bound by
an expression type signature: a2 at test.hs:3:12
`a' is a rigid type variable bound by
the type signature for f :: a -> a at test.hs:1:6
In the expression: x :: a
In an equation for x': x' = x :: a
In the expression: let x' = x :: a in x
我做错了什么或者不可能这样做?
答案 0 :(得分:29)
您需要ScopedTypeVariables
扩展才能实现此功能,如下所示:
{-# LANGUAGE ScopedTypeVariables #-}
f :: forall a. a -> a
f x =
let x' = x :: a
in x'
如果你有这样的类型签名
f :: a -> a
然后它表明f
是多态的,适用于a
的任何选择。所以f
可以
用于类型Int -> Int
,类型Bool -> Bool
或类型[Int -> Bool] -> [Int -> Bool]
- 无论您喜欢什么。
如果您有类似这样的类型注释
x :: a
它意味着类似的事情,即x
应该适用于您选择的任何类型。但在你的情况下,情况并非如此。外部函数f
是多态的,但在函数内,x
必须是用户为外部{{{}>选择的相同类型a
1}}。默认情况下,Haskell不会在不同类型签名和注释中出现的类型变量之间建立连接。但是,您可以通过启用x
扩展程序来告知它这样做。现在,通过在ScopedTypeVariables
前添加a -> a
作为前缀,您可以明确指示Haskell将forall a.
视为a
定义中的特定类型变量。如果您随后注释f
,则它引用外部x :: a
而不是新的多态a
。
答案 1 :(得分:5)
对于任何想要输入注释而不是表达式的人 - ScopedTypeVariables
也允许你这样做!
f1 = do
let x :: Int = 5
y :: Int <- someMonadicOperation
return $ x + y
答案 2 :(得分:0)
这应该有效:
f :: s -> s
f x =
let y = undefined :: s
in y
只需使用普通::
运算符,如上例中所示,用于类型注释。
更新
它似乎不适用于多态类型。但它适用于具体类型。
以下类型检查:
f :: Int -> Int
f x = let m = x :: Int
in m
这会产生错误:
f1 :: a -> a
f1 x = let m = x :: a
in m