(如果我的术语有误,请见谅)。
我正在尝试编写一个处理异常的包装函数:如果给定 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/