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

Haskell 如何在let绑定中添加类型注释,haskell,Haskell,我是Haskell的初学者,我发现错误消息很难理解(我想它是随时间而来的)。无论如何,为了帮助我理解我的错误,我尝试在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

我是Haskell的初学者,我发现错误消息很难理解(我想它是随时间而来的)。无论如何,为了帮助我理解我的错误,我尝试在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
我做错了什么事还是不可能做?

这应该可以:

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
解决方案 您需要
ScopedTypeVariables
扩展才能使其工作,如下所示:

{-# LANGUAGE ScopedTypeVariables #-}

f :: forall a. a -> a
f x = 
    let x' = x :: a
    in x'
解释 如果你有这样的类型签名

f :: a -> a
x :: a
然后它表示
f
是多态的,并且适用于
a
的任何选择。所以
f
可能是 用于类型
Int->Int
,或类型
Bool->Bool
,或类型
[Int->Bool]->[Int->Bool]
——随你喜欢

如果您有这样的类型注释

f :: a -> a
x :: a

这意味着类似的事情,即
x
应该可以在您选择的任何类型上使用。但你的情况并非如此。外部函数
f
是多态的,但在该函数中,
x
必须与用户为外部
x
选择的
a
类型相同。默认情况下,Haskell不会在不同类型签名和注释中出现的类型变量之间建立连接。但是,您可以通过启用
ScopedTypeVariables
扩展来告诉它这样做。现在,通过在
a->a
前面加上
作为所有a.
的前缀,您可以明确指示Haskell使
a
作为
f
定义中的特定类型变量可见。如果您随后注释
x::a
,它指的是外部
a
,而不是一个新的多态
a

,对于任何希望为绑定而不是表达式进行类型注释的人来说-
ScopedTypeVariables
也允许您这样做

f1 = do
  let x :: Int = 5
  y :: Int <- someMonadicOperation
  return $ x + y
f1=do
设x::Int=5

你说的“你还没有定义函数本身”是什么意思?如果我删除类型注释,该函数将得到很好的定义和运行。第三个示例基本上是我的问题,它为什么不工作?抱歉,它不适用于多态类型。使用komiskus解释的
ScopedTypeVariables
扩展。我假设您正确地编写了
fx=…
,而不是
let fx=…
哇,我已经找了很久了!