HLint建议我使用forM_而不是forM.为什么?我看到他们有不同类型的签名,但没有找到一个很好的理由使用一个而不是另一个.
forM :: (Traversable t, Monad m) => t a -> (a -> m b) -> m (t b)
forM_ :: (Foldable t, Monad m) => t a -> (a -> m b) -> m ()
Run Code Online (Sandbox Code Playgroud)
Die*_*Epp 25
该forM_功能更有效,因为它不会保存操作的结果.就这些.(这在使用monad时才有意义,因为类型的纯函数a -> ()不是特别有用.)
0xA*_*xAX 11
好,
forM is mapM with its arguments flipped.
forM_ is mapM_ with its arguments flipped.
Run Code Online (Sandbox Code Playgroud)
我们在mapM和mapM_中看到:
mapM :: Monad m => (a -> m b) -> [a] -> m [b]
Run Code Online (Sandbox Code Playgroud)
mapM mf xs采用monadic函数mf(具有类型Monad m => (a -> m b))并将其应用于列表中的每个元素xs; 结果是monad中的列表.mapM和之间的区别mapM_是,mapM返回结果列表,同时mapM_返回空结果.mapM_不存储每个操作的结果.
要理解(A) :forM xs f和(B) :之间的区别forM_ xs f,比较以下各项之间的区别可能会有所帮助:
-- Equivalent to (A)\ndo\n r1 <- f x1\n r2 <- f x2\n ...\n rn <- f xn\n return [r1, r2, ..., rn]\n\n-- Equivalent to (B)\ndo\n _ <- f x1\n _ <- f x2\n ...\n _ <- f xn\n return ()\nRun Code Online (Sandbox Code Playgroud)\n\n关键的区别在于forM_忽略结果r1,...rn并且仅通过返回空结果return ()。将下划线视为“不关心”的意思...forM_ 不关心结果。forM但是,确实关心结果并通过return [r1, r2, ... rn].
示例 1 \n下面的代码询问您的姓名 3 次并打印 forM 的结果。
\n\nimport Control.Monad (forM, forM_)\n\nmain = do\n let askName i = do\n putStrLn $ "What\'s your name (" ++ (show i) ++ ")"\n name <- getLine\n return name\n results <- forM [1,2,3] askName\n putStrLn $ "Results = " ++ show results\nRun Code Online (Sandbox Code Playgroud)\n\n执行示例forM:
What\'s your name? (1)\n> James\nWhat\'s your name? (2)\n> Susan\nWhat\'s your name? (3)\n> Alex\nResults = ["James", "Susan", "Alex"]\nRun Code Online (Sandbox Code Playgroud)\n\n但如果我们将 更改forM为 a forM_,那么我们将改为:
What\'s your name? (1)\n> James\nWhat\'s your name? (2)\n> Susan\nWhat\'s your name? (3)\n> Alex\nResults = ()\nRun Code Online (Sandbox Code Playgroud)\n\n在您的情况下,linter 告诉您您没有使用您的返回值forM(您没有foo <- forM xs f,您可能forM xs f在一行上有它自己),因此应该使用forM_。例如,当您使用诸如 之类的单子操作时,就会发生这种情况putStrLn。
示例 2下面的代码询问您的姓名,然后重复 3 次说“Hello”\xe2\x80\x93。
\n\nimport Control.Monad (forM, forM_)\n\nmain = do\n let askThenGreet i = do\n putStrLn $ "What\'s your name (" ++ (show i) ++ ")"\n name <- getLine\n putStrLn $ "Hello! " ++ name\n forM [1,2,3] askThenGreet\nRun Code Online (Sandbox Code Playgroud)\n\n执行示例forM:
What\'s your name? (1)\n> Sarah\nHello! Sarah\n\nWhat\'s your name? (2)\n> Dick\nHello! Dick\n\nWhat\'s your name? (3)\n> Peter\nHello! Peter\n\n[(), (), ()]\nRun Code Online (Sandbox Code Playgroud)\n\n的总体结果main来自于 forM: 的结果[(), (), ()]。它出现在控制台中,非常无用且令人烦恼。但如果我们将 更改forM为 a forM_,那么我们将改为:
What\'s your name? (1)\n> Sarah\nHello! Sarah\n\nWhat\'s your name? (2)\n> Dick\nHello! Dick\n\nWhat\'s your name? (3)\n> Peter\nHello! Peter\nRun Code Online (Sandbox Code Playgroud)\n\n通过这一更改,总体结果来自 和mapM_现在()。这不会显示在控制台中(IO monad 的一个怪癖)!伟大的!\n此外,通过mapM_在这里使用,代码的其他读者会更清楚 \xe2\x80\x93 你间接解释/自我记录你不关心结果[r1, ..., rn] = [(), (), ()]\xe2\x80\x93这是正确的,因为它们在这里毫无用处。