如果我有许多string -> IO ()
的函数,是否有一种整齐的方式将它们全部应用于单个值。
op1, op2, op3 :: String -> IO ()
main :: IO ()
main = do
let str = "test"
op1 str
op2 str
op3 str
每次都要写出str吗?
答案 0 :(得分:8)
只需使用功能应用程序的地图和部分应用程序($
):
mapM ($ str) [op1,op2,op3]
不想要结果?细
mapM_ ($ str) [op1,op2,op3]
或使用Data.Foldable
:
for_ [op1,op2,op3] ($ str)
编辑:
扩展for_
替代forM_
的评论。
mapM
/ mapM_
也是如此。这些是历史的工件 - 这些操作专门针对Monads,并且可以被删除。适用的替代方案是traverse
和traverse_
。
答案 1 :(得分:2)
我建议采用for_
或traverse_
方法,但请注意这些Monoid
个实例存在:
Monoid b => Monoid (a -> b)
Monoid a => Monoid (IO a)
Monoid ()
所以在这种特殊情况下,这有效:
mconcat [op1, op2, op3] str
答案 2 :(得分:1)
我愿意
op1, op2, op3 :: String -> IO ()
main :: IO ()
main = do
let str = "test"
mconcat (sequence [op1, op2, op3] str)
这有点复杂:sequence
此处专门用于输入
[String -> IO ()] -> String -> [IO ()]
而mconcat
只是获取IO操作列表(类型[IO ()]
)并返回单个IO操作(类型IO ()
)。
答案 3 :(得分:0)
另一种解决方案,使用ZipList
中的Control.Applicative
:
let ZipList ios = ZipList [op1,op2,op3] <*> ZipList (repeat str)
in sequence ios