【问题标题】:Process a Either Reply [Maybe ByteString] into a [Maybe Text]将 Either 回复 [Maybe ByteString] 处理成 [Maybe Text]
【发布时间】:2021-04-27 10:21:13
【问题描述】:

以下代码使用 Hedis 运行 mget 命令,并将结果作为 [Maybe BS.ByteString] 返回:

-- | Text to ByteString
tbs :: Text -> BS.ByteString
tbs = BS.pack . T.unpack


-- | ByteString to Text
bst :: BS.ByteString -> Text
bst = T.pack . BS.unpack


mgetRedis :: Redis.Connection -> [Text] -> IO [Maybe BS.ByteString]
mgetRedis connection keys =
    runRedis connection action
    where
        action = do

            result <- Redis.mget $ tbs <$> keys
            -- `result` is of type `Either Reply [Maybe BS.ByteString]`

            case result of
                Right values -> pure values
                _            -> pure []

首先,我发现这段代码很乱,想知道有没有办法让它更干净。

其次,我希望 mgetRedis 使用上面编写的 bst 帮助器返回 [Maybe Text]。我不能做pure $ bst &lt;$&gt; values,因为这里有两个解包级别:首先是Maybe,然后是List。有没有什么方法可以让这个函数返回所需的类型而不会淹没在嵌套的case 语句的海洋中?

【问题讨论】:

  • T.pack . BS.unpack 几乎可以肯定是个坏主意。它不仅很慢(因为中间列表,尽管编译器可能会将其融合掉),而且它也忽略了任何编码问题。 text 包提供了 dedicated encoders,这使得这一点变得明确。如果请求失败(?),我也觉得返回一个空列表是可疑的。
  • 感谢您指出专用编码器 - 对于空列表,我同意,替代方案是将 Either 一直带到将处理响应的业务逻辑代码?跨度>

标签: haskell maybe either


【解决方案1】:

您要问的本质上是如何fmap 任意深入一堆函子。这可以通过撰写fmaps 轻松完成:

mgetRedis :: Redis.Connection -> [Text] -> IO [Maybe Text]
mgetRedis connection keys =
    runRedis connection action
    where
        action = do

            result <- Redis.mget $ tbs <$> keys
            -- `result` is of type `Either Reply [Maybe BS.ByteString]`

            case result of
                Right values -> pure $ fmap T.decodeUtf8 <$> values
                      -- equivalent to (fmap . fmap) T.decodeUtf8 $ values
                _            -> pure []

fmap . fmap 模式重复,即您可以使用fmap . fmap . fmap 映射三个深度级别。但到那时,最好将整个堆栈视为单个函子,这可以通过 monad 转换器 来完成。

【讨论】:

  • 谢谢。我还没有完全理解 monad 转换器,但是很高兴知道这可能是他们的一个用例。会调查的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-11-23
  • 1970-01-01
  • 2020-11-16
  • 2022-01-12
  • 1970-01-01
  • 2021-01-04
  • 1970-01-01
相关资源
最近更新 更多