关于haskell:避免foldM中的do语句

Avoiding do statement in foldM

1
2
3
4
g ll =
  foldlM (\\ some_list b -> do
    part <- f b
    return (some_list ++ part)) [] ll

在上面的代码中,我使用 do statement 只是因为 f 函数返回一个单子类型: M a 其中 a 是一个列表。
(我用 <-"解压"该列表。这就是我需要 do statement 的原因)。我可以避免它并写得更简洁吗? (是的,我知道我可以使用 >>= 编写它,但我也考虑使用更好的方法。)


foldlM 是适合这项工作的错误工具。正如 chepner 的回答所示,您可以使用它,但是连接列表的方式可能会变得昂贵。 Luka Rahne 的单线更好:

1
g ll = fmap concat (mapM f ll)

另一种选择是直接使用foldr

1
g = foldr (\\x r -> (++) <$> f x <*> r) (pure [])

另一种编写第二个版本的方法,通过内联 foldr:

1
2
g [] = pure []
g (x : xs) = (++) <$> f x <*> g xs


你的 do 表达式

1
2
3
do
  part <- f b
  return (some_list ++ part)

遵循 fmap 捕获的提取-应用-返回模式(由于身份 fmap f k = k >>= return . f

  • 您从计算 f b 中提取 part
  • 您将 (some_list ++) 应用于 part
  • 您返回该应用程序的结果。
  • 这可以通过 fmap:

    一步完成

    1
    2
    -- foldlM (f b >>= return . (some_list ++)) [] ll
    foldlM (\\some_list b -> fmap (some_list ++) (f b)) [] ll