【问题标题】:Is `forM_` idiomatic Haskell?`forM_` 是惯用的 Haskell 吗?
【发布时间】:2016-08-23 11:47:09
【问题描述】:

我倾向于在 Haskell 中使用 forM_,这很像 Ruby 中的 .each 或 Scala 中的 foreach

import Control.Monad (forM_)
import Network.BSD (getHostByName, hostAddresses)
import Network.Socket (inet_ntoa)
import System.Environment (getArgs)

resolve address = do
  ent <- getHostByName address
  mapM inet_ntoa (hostAddresses ent)

main = do
  args <- getArgs
  args `forM_` (\address -> do
    ips <- resolve address
    ips `forM_` (\ip -> putStrLn $ address ++ "\t" ++ ip))

这对我来说似乎并不习惯,但使用 mapM_ 似乎很笨拙。有没有一种惯用的方式来重写这段代码?

【问题讨论】:

  • 不是重复的,但我觉得my answer here 很好地解决了这个问题。我想说像这样使用forM_ 完全没问题。 (除了 phadej 说的,for_ 是更现代的替代品,但实际上它们之间通常没有区别。)

标签: haskell


【解决方案1】:

是的,尽管您最好只使用来自Data.Foldablefor_ :: (Foldable t, Applicative f) =&gt; t a -&gt; (a -&gt; f b) -&gt; f ()

同样通过使用它作为前缀(即普通函数),代码看起来像一个“普通的”命令式代码:

main = do
    args <- getArgs
    for_ args $ \address -> do
        ips <- resolve address
        for_ ips $ \ip -> putStrLn $ address ++ "\t" ++ ip

附: ApplicativeMonadic“遍历”的版本:

  • mapM ~ traverse
  • mapM_ ~ traverse_
  • forM ~ for
  • forM_ ~ for_

【讨论】:

  • 这些操作本质上是Applicative。有更自然单子的版本。 traverseM :: (Monad m, TraversableM t) =&gt; (s -&gt; a -&gt; m (s, b)) -&gt; t a -&gt; m (t b)。后者可以使用StateT 强制转换为Traversable,但我很确定当你想要一个 McBride 风格的索引单子时它会停止工作。
  • 不错的答案!正是我想要的!
【解决方案2】:
main = getArgs >>= mapM_ (\address ->
  resolve address >>= mapM_ (\ip ->
    putStrLn $ address ++ "\t" ++ ip))

一旦我们有了ArgumentDo,我们就不必将那个 lambda 表达式括起来。

ListT 也恰好适用:

main = void $ runListT $ do
  address <- ListT getArgs
  ip <- ListT $ resolve address
  liftIO $ putStrLn $ address ++ "\t" ++ ip

【讨论】:

  • mapM_ 可能。不过,我不确定代码打高尔夫球是否真的有用。
  • address 来自哪里?
  • 哎呀,没注意到。顺便说一句,打高尔夫球刚刚从移除fors的过程中出现。编辑。
  • 这种使用transformers ListT 在 Stephen Shaws 案中可能是可以容忍的,但它会招致灾难。这是对即将发生的空间泄漏的标准描述。
  • 请参阅lpaste.net/179912,在我的计算机上,当它使用“正确完成的 ListT”时,这些数字会更慢——因为它是通过列表操作进行翻译的。但是变形金刚版本几乎耗尽了内存,如果任一数字增加,都会耗尽内存。流式 ListT 使用常量内存,尽管它必须一直构造列表。
猜你喜欢
  • 1970-01-01
  • 2020-07-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-08
  • 2020-11-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多