将IO [Maybe String]过滤为IO [String]

10

如何使用 >>= 过滤 IO [Maybe String],只保留列表中的 Just 值并保持 IO 上下文。

-- returns Just, if the passed binary-name is not present on the system
binDoesntExist :: String -> IO (Maybe String)
binDoesntExist ...

我的当前解决方案没有使用绑定运算符:

missingBin :: [String] -> IO [String]
missingBin xs = do
  ys <- mapM (\x -> binDoesntExist x) xs
  return $ catMaybes ys

我目前正在学习 Haskell 并尝试理解如何使用标准库中的不同函数。我的解决方案可行,但我想有更简洁的方式。


5
只是为了好玩,你实际上可以用撇号给它命名为 binDoesn'tExist,它依然可以工作。 - Daniel Wagner
2个回答

10

一个简短的解决方案是

missingBin :: [String] -> IO [String]
missingBin = fmap catMaybes . mapM binDoesntExist

对此,您并不需要使用>>=运算符。

注意:(\x -> binDoesntExist x) = binDoesntExist


5

从您在binDoesntExist上的评论中,我怀疑您可能更喜欢不同的类型签名,即:

-- returns True if the passed binary is not present on the system
binDoesntExist :: String -> IO Bool
binDoesntExist = ...

这种签名的实现可能比您现有的实现更简单;而且,您的missingBin也会简单得多:

missingBin :: [String] -> IO [String]
missingBin = filterM binDoesntExist

这个讨论假设你现有的函数总是返回与传递给它的String完全相同的结果(如果它返回任何String的话)。但这个假设对我来说并不过分。

你关于将 missingBin 转换为 IO Bool 是正确的。在理解 Haskell 工作原理之后,难点在于学习如何思考 Haskell。感谢你的提示。 - Paradiesstaub

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接