haskell - 如何指定内联类型中使用的类型变量,是否与函数定义中使用的类型变量相同?

标签 haskell type-inference type-variables

(如果我的术语有误,请见谅)。

我正在尝试编写一个处理异常的包装函数:如果给定 IO Action 抛出,返回 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 这些是相同的类型呢?

最佳答案

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

{-# LANGUAGE ScopedTypeVariables #-}

...

tryMaybe :: forall a . IO a -> IO (Maybe a)
...
forall语法带来了类型变量 a进入 tryMaybe 的整个主体的范围,而不是仅限于默认的类型签名。这主要是历史异常,而不是故意设计。

关于haskell - 如何指定内联类型中使用的类型变量,是否与函数定义中使用的类型变量相同?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24395881/

相关文章:

haskell - 应用函数两次编译错误Haskell

haskell - GHC/GHCi 意外接受的代码

typescript - TS 错误地推断路口类型

haskell - 应用实例化中的刚性变量

haskell - ScopedTypeVariables 无法与嵌套的 where 子句一起使用?

c++ - GHCi 无法在 Windows 上加载 .dll 库(C++ 库)

haskell - 量化约束与(封闭)类型族

Haskell - 函数不适用于无限列表

type-inference - Idris 可以推断顶级常量类型的索引吗?

python - 受约束的 TypeVar 和 Union 之间有什么区别?