【问题标题】:How do I specify a type variable used in an inline type, is the same as a type variable used in a function definition?如何指定内联类型中使用的类型变量,是否与函数定义中使用的类型变量相同?
【发布时间】:2014-06-24 20:42:06
【问题描述】:

(抱歉,如果我的术语有误)。

我正在尝试编写一个处理异常的包装函数:如果给定的IO 动作抛出,它返回Nothing(当然在IO 上下文中),但如果给定的IO 动作成功,它返回Just v

tryMaybe :: IO a -> IO (Maybe a)
tryMaybe action = do
    result <- (try action) :: IO (Either SomeException a)
    return $ case result of
        Left _  -> Nothing
        Right v -> Just v

这会导致编译器错误消息:

  Couldn't match type `a' with `a1'
      `a' is a rigid type variable bound by
          the type signature for tryMaybe :: IO a -> IO (Maybe a)
          at src/Database.hs:33:13
      `a1' is a rigid type variable bound by
           an expression type signature: IO (Either SomeException a1)
           at src/Database.hs:35:15
    Expected type: IO a1
      Actual type: IO a
    In the first argument of `try', namely `action'

我猜第一行中的类型变量a 与第三行中的a 不同——它们恰好在源代码中具有相同的名称,并且编译器具有在错误消息中将其重命名为a1

那么我如何告诉 Haskell 这些是相同的类型呢?

【问题讨论】:

标签: haskell type-inference type-variables


【解决方案1】:

需要开启ScopedTypeVariables扩展,并将顶层函数的类型签名改为forall a .开头:

{-# LANGUAGE ScopedTypeVariables #-}

...

tryMaybe :: forall a . IO a -> IO (Maybe a)
...

forall 语法将类型变量a 带入tryMaybe 整个主体的范围内,而不是仅限于默认的类型签名。这主要是历史上的反常现象,而非刻意的设计。

【讨论】:

  • 啊哈是的,它排序了。我知道 GHC 在这里试图保持与 Haskell 98 的向后兼容性,但我会想到关于类型变量阴影的警告(如果这是正确的术语),加上调查该语言扩展的提示,可能对像我这样的新手有帮助.啊,我生活和学习。非常感谢!
  • @stusmith 我认为阴影警告是个好主意。您应该提交 ghc 增强票。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多