if I have a number of functions that are string -> IO ()
, is there a tidy way to apply them all to a single value in sequence.
op1, op2, op3 :: String -> IO ()
main :: IO ()
main = do
let str = "test"
op1 str
op2 str
op3 str
with out having to write out str each time?
Just use a map and partial application of function application ( $
):
mapM ($ str) [op1,op2,op3]
Don't want the result? Fine.
mapM_ ($ str) [op1,op2,op3]
Or use Data.Foldable
:
for_ [op1,op2,op3] ($ str)
EDIT:
Expanding on the commentary of for_
being a replacement for forM_
.
The same can be said about mapM
/ mapM_
. These are artifacts of history - the operations are specialized to Monads and could, argueably should, be deleted. The Applicative alternative is traverse
and traverse_
.
I'd recommend the for_
or traverse_
approach, but note that these Monoid
instances exist:
Monoid b => Monoid (a -> b)
Monoid a => Monoid (IO a)
Monoid ()
So in this particular case, this works:
mconcat [op1, op2, op3] str
I would do
op1, op2, op3 :: String -> IO ()
main :: IO ()
main = do
let str = "test"
mconcat (sequence [op1, op2, op3] str)
This is somewhat complicated: sequence
here is specialized to type
[String -> IO ()] -> String -> [IO ()]
while mconcat
simply takes a list of IO actions (type [IO ()]
) and returns a single IO action (type IO ()
).
Another solution, this one using ZipList
from Control.Applicative
:
let ZipList ios = ZipList [op1,op2,op3] <*> ZipList (repeat str)
in sequence ios
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.