haskell - 如何不对使用更通用函数的受限函数应用实例约束?
问题描述
假设我有一个功能:
logResult :: (MonadIO m, ToJSON a) => Either MyError (Response a) -> m ()
logResult = ...
在这个函数中,如果我得到:
Right (Response a)
- 我打电话toJSON
记录结果。Left MyError
- 我也记录下来。MyError
已经ToJSON
定义了一个实例。
现在我想写一个辅助函数:
logError :: (MonadIO m) :: MyError -> m ()
logError err = logResult (Left err)
但 GHC 抱怨如下:
• Could not deduce (ToJSON a0) arising from a use of ‘logResult’
from the context: MonadIO m
bound by the type signature for:
logError :: forall (m :: * -> *).
MonadIO m =>
L.Logger
-> Wai.Request
-> MyError
-> m ()
...
...
The type variable ‘a0’ is ambiguous
我理解错误是因为logResult
需要保证a
inResponse a
必须ToJSON
定义一个实例。但在logError
我明确通过Left MyError
. 这不应该消除歧义吗?
有什么办法可以编写logError
辅助函数吗?
PS:我已经简化了示例中的类型签名。错误消息有血淋淋的细节。
解决方案
为什么这是一个功能?如果这个函数的行为如此干净地分成两个,那么它应该是两个函数。也就是说,您已经编写了一个整体函数,并试图将一个更简单的函数定义为使用它的实用程序。相反,编写一个简单的函数并将单体函数编写为它与另一个函数的组合。该类型非常需要它:Either a b -> c
与(a -> c, b -> c)
.
-- you may need to factor out some common utility stuff, too
logError :: (MonadIO m) :: MyError -> m ()
logResponse :: (MonadIO m, ToJSON a) => Response a -> m ()
logResult :: (MonadIO m, ToJSON a) => Either MyError (Response a) -> m ()
logResult = either logError logResponse
logResult
仍然有它的用途;如果你Either MyError (Response a)
从某个图书馆得到一个,那么logResult
可以毫不费力地处理它。但是,否则,您不应该写作logResult (Left _)
或logResult (Right _)
经常写作;本质上将logResult . Left
andlogResult . Right
视为它们自己的函数,这使您回到实际将它们编写为单独的函数。
但在
logError
我明确通过Left MyError
. 这不应该消除歧义吗?
不,不应该。问题的结束和开始是logResult
这样的:
logResult :: (MonadIO m, ToJSON a) => Either MyError (Response a) -> m ()
当你调用它时,实现并不重要。类型说你需要ToJSON a
——你需要提供ToJSON a
. 而已。如果您知道不需要ToJSON a
值Left
,那么您就拥有未反映在类型中的有用信息。您应该将该信息添加到类型中,在这种情况下,这意味着将其分成两部分。(IMO)实际上是错误的语言设计来允许您的想法,因为停止问题应该使其无法正确执行。
推荐阅读
- python - DirectWrite 未针对变音符号进行调整
- javascript - 解析 JavaScript modal 的打开和关闭
- python - BOTO3 使用 Python 获取 EC2 列表的信息
- php - 如何导航 xml / xmlns 以提取 PHP 中的值和属性?
- c - 返回指向局部变量的指针是UB吗?
- gradle - Android 单元测试套件在个别测试通过时挂起
- git - 使用 git rev-list(或任何其他管道命令)访问 reflog 主题
- php - 将二进制/unicode字符串与普通字符串进行比较和修剪?
- c++ - 带有stl的模板成员函数
- json - 无法添加对象和字符串时获取值