1

Suppose I have a list of tuples (e.g. [(a,b)]) each a result of some previous computation.

And I want several functions to be applied on each of these elements (e.g one function might print it another send it over the network etc.)

What I've tried:

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"

prints just "Yo".

George Ni
  • 13
  • 4

3 Answers3

4

If you look closely res has type [IO ()] and you never use it.

So just sequence it:

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"

in case you want to know how you could right the complete block more concise than you could refactor the list of mappings (using sections), go with print (which is basically your putStrLn . show) and mapM_:

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

which will give

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

as well ;)


note that you probably should not mix all the IO stuff with the purer computations - instead I would refactor the list of integers out:

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

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

(of course introducing functions as you go along, but I cannot guess what you are trying to achieve here)

from this you gain the ability to just check your pure functions/values:

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

and gain probably a lot of readability ;)

Random Dev
  • 51,810
  • 9
  • 92
  • 119
  • Is there some more concise or 'Haskelish' form to write this (possibly as a whole and not just the sequencing assuming the list of results is actually a return value of some `foo`)? – George Ni Nov 11 '15 at 13:13
  • I think [`sequence`](https://hackage.haskell.org/package/base-4.8.1.0/docs/Prelude.html#v:sequence) **is** just this (if you have your list `actions :: [IO foo]`s then `sequence actions :: IO [foo]` so you will get a list with your `foo`s - of course you would want to use it like `foos <- sequence actions` inside `main`s do block then) – Random Dev Nov 11 '15 at 13:18
  • @GeorgeNi I have added another version are you talking about this? – Random Dev Nov 11 '15 at 13:32
  • Yes that was exactly what I was hoping for! – George Ni Nov 11 '15 at 14:05
0

If you have a list of ios :: [a -> IO b] you could use mapM ($ aValue) ios to get IO [b] or mapM_ to get IO ()

epsilonhalbe
  • 15,637
  • 5
  • 46
  • 74
0

let doesn't bind anything into the monad. So IO doesn't care what you do with <*> to apply functions in a list, as long as you don't use the result in any way in a monad action.

To simply execute a list of actions in... well, sequence, you can use sequence:

    let res = fs <*> a
    sequence res
leftaroundabout
  • 117,950
  • 5
  • 174
  • 319