如何在let绑定中添加类型注释

时间:2014-03-16 11:45:18

标签: haskell

我是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

我做错了什么或者不可能这样做?

3 个答案:

答案 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