在同一个输入上调用多个 IO 函数

Call multiple IO functions on the same input

假设我有一个元组列表(例如 [(a,b)]),每个元组都是先前计算的结果。

而且我想在这些元素中的每一个上应用几个函数(例如,一个函数可能打印它,另一个函数通过网络发送它等)

我尝试过的:

import Control.Applicative
main = do
          let a = [1..5]
          let fs = [(\k-> putStrLn $ show $ k*2), (\k-> putStrLn $ show $ k-2), (\k-> putStrLn $ show $ k*10)]
          let res = fs <*> a 
          putStrLn $ "Yo"

仅打印 "Yo".

如果你仔细观察 res 有类型 [IO ()] 而你从不使用它。

所以只是sequence它:

main = do
  let a = [1..5]
  let fs = [(\k-> putStrLn $ show $ k*2), (\k-> putStrLn $ show $ k-2), (\k-> putStrLn $ show $ k*10)]
  let res = fs <*> a
  sequence res
  putStrLn $ "Yo"

如果您想知道如何使整个块更简洁,而不是重构映射列表(使用 部分 ),请选择 print (这基本上是你的 putStrLn . show)和 mapM_:

main = do
  mapM_ print $ [(* 2), (+ (-2)), (* 10)] <*> [1..5]
  putStrLn $ "Yo"

这会给

λ> :main
2
4
6
8
10
-1
0
1
2
3
10
20
30
40
50
Yo

还有 ;)


请注意,您可能不应该将所有 IO 内容与更纯粹的计算混合在一起 - 相反,我会重构整数列表:

myCombinations :: [Int] -> [Int]
myCombinations ns = [(* 2), (+ (-2)), (* 10)] <*> ns

main = do
  mapM_ print $ myCombinations [1..5]
  putStrLn $ "Yo"

(当然会边走边介绍功能,但我猜不出你想在这里实现什么)

由此您可以只检查您的纯 functions/values:

λ> myCombinations [1..5]
[2,4,6,8,10,-1,0,1,2,3,10,20,30,40,50]

并可能获得很多可读性;)

如果您有 ios :: [a -> IO b] 的列表,您可以使用 mapM ($ aValue) ios 获取 IO [b] 或使用 mapM_ 获取 IO ()

let 不会将任何东西绑定到 monad 中。所以 IO 不关心你用 <*> 做什么来应用列表中的函数,只要你不以任何方式在 monad 操作中使用结果。

要简单地执行一系列操作......好吧,序列,您可以使用sequence:

    let res = fs <*> a
    sequence res