【问题标题】:Haskell: Filtering through a dictionary/hash/map with IO() valuesHaskell:通过具有 IO() 值的字典/哈希/映射进行过滤
【发布时间】:2012-02-14 03:40:48
【问题描述】:

我有一个函数,它的签名是 String -> String -> IO (Maybe String) 现在,我使用此函数为字典构建值,最终得到: [(String,IO (Maybe String))]

我必须分析字典中的值并根据结果返回适当的键。我希望只在 Map 上使用过滤器来逐步完成它,但我想不出一种方法来即时提取该 IO 操作。那么如何映射/过滤运行 IO 操作的字典并根据 IO 操作的值返回字典的适当键的结果?有没有简单的方法,或者我只是把自己弄得一团糟?

谢谢。

【问题讨论】:

  • 如果我理解正确,您的问题是您实际上并不希望地图包含 IO 操作,而是运行它们的结果。所以问题不在于如何过滤包含 IO 动作的映射,而是如何构建包含这些 IO 动作结果的映射。如果您需要这方面的帮助,我们需要查看构建地图的代码。
  • @hammar 感谢您的回复,但我认为生成地图的代码不相关,因为我可以简单地以“给定带有签名的地图 [(String,IO (Maybe String)) ] ... blah blah" 是的,你理解正确。我需要根据作为地图值的 IO 操作的结果来过滤地图。所以在伪代码中是这样的: superFilter (\x -> ioResultOf x /= Nothing && == "01") theMap.

标签: haskell


【解决方案1】:

也许解决方案是将sequence 与类似的东西一起使用

sequence . map (\(a,mb) -> (mb >>= \b -> return (a,b)))

然后您可以简单地使用liftM 将您的过滤器应用于生成的IO [(String,Maybe String)]

liftM 在 Control.Monad 中。或者,在 do 表示法中

myFilter :: (String,(Maybe String)) -> Bool) 
            -> [(String,IO (Maybe String))] 
            -> IO [(String,(Maybe String))]
myFilter f ml =
   do
       l <- sequence . map (\(a,mb) -> (mb >>= \b -> return (a,b))) $ ml
       return $ filter f ml

也许需要进行一些重构。通常在使用 monad 时,您希望使用 mapM 而不是 map

Control.Monad 中还有一个filterM 函数。这可能是您需要的。


编辑:在 cmets 中指出

sequence . map (\(a,mb) -> (mb >>= \b -> return (a,b))) $ ml

等价于

mapM (\(a,mb) -> fmap ((,) a) mb) ml

所以

myFiter' f = (liftM $ filter f) .  mapM (\(a,mb) -> fmap ((,) a) mb)

【讨论】:

  • 谢谢。我会试试这个并报告...... :)
  • mapM f = sequence . map f,和foo &gt;&gt;= return . bar = fmap bar foo;因此我推荐l &lt;- mapM (\(a,mb) -&gt; fmap ((,) a) mb) ml。您实际上可以将该 lambda 写为 (uncurry $ fmap . (,)) 但这开始变得晦涩难懂。
  • 使用Data.Traversable的泛化序列,如果是(,) o was already an instance of Traversable,则可以使用f :: [(String, IO (Maybe String))] -&gt; IO [(String, Maybe String)] ; f = mapM sequence
【解决方案2】:

我有一个签名为String -&gt; String -&gt; IO (Maybe String) 的函数现在,我使用此函数为字典构建值,最终得到:[(String,IO (Maybe String))]

这部分不适合我。如何只输入 2 个字符串,并最终得到 [(String, IO (Maybe String))] 类型的有意义的结果?

缺乏细节,假设你的情况是这样的:

f :: String -> String -> IO (Maybe String)
magic :: String -> (String, String)

magic 获取一些密钥,并以某种方式将密钥拆分为f 所需的两个输入字符串。所以,假设你有一个键列表,你会得到一个像这样的[(String, IO (Maybe String))]

-- ks :: [String]
myMap = map (\k -> let (a,b) = magic k in (k, f a b)) ks

但是...如果我们有一个 [(String, Maybe String)] 代替会更好吗?假设我们在一个 IO 动作中......

someIOAction = do
  ...
  myMap <- monadicMagicks (\k -> let (a,b) = magic k in (k, f a b)) ks

但是我们可以用什么monadicMagicks 来解决这个问题?让我们看看我们期望从这些表达式中得到的类型

monadicMagicks (\k -> ...) ks             :: IO [(String, Maybe String)]
(\k -> let (a,b) = magic k in (k, f a b)) :: String -> (String, IO (Maybe String))
ks                                        :: [String]

-- therefore
monadicMagicks :: (String -> (String, IO (Maybe String)))
               -> [String]
               -> IO [(String, Maybe String)]

停止...胡歌时间。让我们先概括一下我们正在寻找的东西。我们这里有两种基本数据类型:String,似乎是“输入”,Maybe String,似乎是“输出”。因此,让我们将String 替换为a,将Maybe String 替换为b。所以我们正在寻找(a -&gt; (a, IO b)) -&gt; [a] -&gt; IO [(a, b)]。人力资源管理系统。未找到结果。好吧,如果我们能得到一个只有IO [b] 的结果类型,那么在一个do 块中我们可以把它从IO 中取出,然后zip 它和原来的键列表一起使用。这也意味着我们输入的函数不必执行 key 与 result 的配对。因此,让我们简化我们正在寻找的内容并重试:(a -&gt; IO b) -&gt; [a] -&gt; IO [b]。嘿,看看吧! mapM 完美匹配该类型签名。

monadicMagicks :: (a -> IO b) -> [a] -> IO [(a, b)]
monadicMagicks f xs = do
  ys <- mapM f xs
  return $ zip xs ys

这实际上可以写得更简洁,并使用更通用的类型签名:

monadicMagicks :: Monad m => (a -> m b) -> [a] -> m [(a, b)]
monadicMagicks f xs = zip xs `liftM` mapM f xs

someIOAction = do
  ...
  -- Like we said, the lambda no longer has to pair up the key with the result
  myMap <- monadicMagicks (\k -> let (a,b) = magic k in f a b) ks

如果您对函数组合感到满意,最后一行也可以改写一点:

  myMap <- monadicMagicks (uncurry f . magic) ks

请注意,monadicMagicks 对于某些 monad 可能没有多大意义,这可能是它不在标准库中的原因。 (例如,在列表 monad 中使用 mapM 通常意味着结果的长度与输入的长度不同):

ghci> mapM (\x -> [x, -x]) [1,2]
[[1,2],[1,-2],[-1,2],[-1,-2]]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-10-11
    • 2022-07-25
    • 1970-01-01
    • 1970-01-01
    • 2018-11-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多