简体   繁体   中英

Haskell: Running a list of IO operations over a single value

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM