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

Posted

技术标签:

【中文标题】如何指定内联类型中使用的类型变量,是不是与函数定义中使用的类型变量相同?【英文标题】: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 这些是相同的类型呢?

【问题讨论】:

你试过ScopedTypeVariables吗? 相关解释在这里:***.com/questions/15800878/… 【参考方案1】:

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

-# LANGUAGE ScopedTypeVariables #-

...

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

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

【讨论】:

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

以上是关于如何指定内联类型中使用的类型变量,是不是与函数定义中使用的类型变量相同?的主要内容,如果未能解决你的问题,请参考以下文章

内联函数,宏定义,内存对齐,类型转换

C++中宏替换与内联函数的区别

C++引用,内联函数,函数重载二义性总结_C++

常量与变量的数据类型转换

预处理conststatic与sizeof-内联函数与宏有什么区别

inline类型的成员函数