ect*_*der 10 haskell typeclass
假设我有一个函数:
logResult :: (MonadIO m, ToJSON a) => Either MyError (Response a) -> m ()
logResult = ...
Run Code Online (Sandbox Code Playgroud)
在此功能中,如果得到:
Right (Response a)
-我打电话toJSON
记录结果。Left MyError
-我也记录了。MyError
已经ToJSON
定义了一个实例。现在,我想编写一个辅助函数:
logError :: (MonadIO m) :: MyError -> m ()
logError err = logResult (Left err)
Run Code Online (Sandbox Code Playgroud)
但是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
Run Code Online (Sandbox Code Playgroud)
我了解该错误是因为logResult
需要保证a
in中Response a
必须ToJSON
定义了一个实例。但是logError
我明确地过去了Left MyError
。这不应该消除歧义吗?
有什么办法可以编写logError
辅助函数?
PS:我已经简化了示例中的类型签名。错误消息中包含详细信息。
HTN*_*TNW 11
为什么这是一个功能?如果此函数的行为如此清晰地分为两个,则应为两个函数。也就是说,您已经编写了一个整体函数,并尝试使用它来将一个简单的函数定义为实用程序。而是编写一个简单的函数,然后将整体函数与另一个函数一起编写。该类型几乎要求它:与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
Run Code Online (Sandbox Code Playgroud)
logResult
仍然有其用途;如果您是Either MyError (Response a)
从某个图书馆获得的,则logResult
可以轻松处理。但是,否则,您不应该写作logResult (Left _)
或logResult (Right _)
经常写作;基本上对待logResult . Left
,并logResult . Right
作为自己的功能,你回实际编写它们作为独立的功能导致。
但是
logError
我明确地过去了Left MyError
。这不应该消除歧义吗?
不,不应该。问题的结尾和开头logResult
看起来像这样:
logResult :: (MonadIO m, ToJSON a) => Either MyError (Response a) -> m ()
Run Code Online (Sandbox Code Playgroud)
调用它时,只需单击一下即可实现。类型表明您需要ToJSON a
-您需要提供ToJSON a
。而已。如果你知道你并不需要做ToJSON a
的Left
值,那么你就拥有未体现在类型有用的信息。您应该将该信息添加到类型中,在这种情况下,这意味着将其分成两个部分。IMO(IMO)实际上不会允许您考虑所想的语言设计,因为停顿问题将使其无法正确执行。
归档时间: |
|
查看次数: |
89 次 |
最近记录: |