Haskell:从多个可能中生成一个数组

时间:2019-01-08 14:35:38

标签: haskell

我有一个简单的问题,但是我找不到合适的解决方案。 我有这样的功能:

getFoos :: Maybe Int
        -> Maybe Int
        -> Maybe Int
        -> [(String, Int)]
getFoos ma mb mc = ...

我想创建以下数组:[("A": 1), ("B": 2), ("C": 3)]。 但这仅是三个参数都是Just!如果一个或多个为Nothing,它们将不会出现在结果数组中。 有什么优雅的方法可以做到这一点吗?

有关信息,我功能的真正签名是:

 getQuerySelect :: Maybe Token
                -> Maybe DeviceId
                -> Maybe SensorId
                -> Maybe Int
                -> Maybe Int
                -> Maybe Int
                -> Maybe UTCTime
                -> Maybe UTCTime
                -> [(String, String)]

用于MongoDB数据库查询。

到目前为止,我的设计是

  getQuerySelect mdev msen ... = do
  let selDev = [("device_id", dev) | (Just (DeviceId dev)) <- [mdev]]
  let selSen = [("sensor_id", sen) | (Just (SensorId sen)) <- [msen]]
  ...
  return $ selDev <> selSen <> ...

有效,但在我看来还是有点尴尬。

1 个答案:

答案 0 :(得分:3)

如果您希望它“很好地扩展以容纳更多Maybes”,则首先使用数组:

getFoosArr :: [Maybe Int] -> [(String, Int)]

实现可以是例如:

getFoosArr = catMaybes . zipWith (\a -> fmap (a,)) [A..]

首先我们用字母 1 标记每个Maybe Int,然后只需用Just过滤掉catMaybes s。

当然,您的原始函数只需要传递参数即可:

getFoos ma mb mc = getFoosArr [ma, mb, mc]

如果您具有异构类型,但是无论如何都希望将其全部转换为String,则很容易;使getFoosArr[Maybe String],并在进一步传递之前转换Just s:

getFoosHet ma mb mc = getFoosArr 
                      [ fmap showA ma
                      , fmap showB mb
                      , fmap showC mc
                      ]

我假设showA :: A -> Stringma :: Just A


1 我已经将\a b -> fmap (a,) b简化为\a -> fmap (a,)。也可以将其写为fmap . (,),但我个人认为它的可读性较差。