繁体   English   中英

Haskell 在提升结果的同时遍历和过滤列表

[英]Haskell traverse and filter through a list while lifting results

假设我有要执行以下操作的代码:

  1. 输入:字符串列表[String]
  2. 操作( checkSatcheckResult
    • 从输入字符串中获取布尔值。
  3. 输出:
    • 如果输入中的所有内容都可解析为布尔值,则仅返回导致“未饱和”的内容。
    • 如果其中至少一个有错误,则返回错误。
data Err = Err String deriving (Show)

-- Detail omitted for this example
checkSat :: String -> Either Err String
checkSat = Right . id

checkResult :: String -> Either Err Bool
checkResult "sat"    = Right True
checkResult "unsat"  = Right False
checkResult err      = Left $ Err err

onlyUnsat :: [String] -> Either Err [String]
onlyUnsat xs = filter (traverse notSat xs) xs
  where notSat x  = fmap not $ checkSat x >>= checkResult
        onlyUnsat = filter (traverse notSat xs) xs

上面的代码不太好用。 用正确的打字方式写onlyUnsat的正确方法是什么?

尝试这个:

onlyUnsat :: [String] -> Either Err [String]
onlyUnsat = traverse checkSat >=> filterM (fmap not . checkResult)

  where

  filterM :: Applicative m => (a -> m Bool) -> [a] -> m [a]
  filterM p = fmap (map fst . filter snd) . traverse (\x -> withFst x <$> p x)
    where withFst x = \y -> (x, y)

  (>=>) :: Monad m => (a -> m b) -> (b -> m c) -> a -> m c
  f >=> g = \x -> f x >>= g

请注意, filterM>=>都可以从Control.Monad导入。 为了清楚起见,我在这里重新定义了它们:-)

基本思想是将操作分为两个阶段:(1)对列表中的每个项目应用checkSat (2) 过滤列表中的每个项目。 第一阶段由traverse checkSat给出,其类型为[String] -> Either Err [String] 第二阶段由filterM (fmap not . checkResult)给出,它也有类型[String] -> Either Err String 然后我们使用>=>将这两个计算链接在一起,形成一个相同的类型。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM