Reputation: 698
I have
functions :: IO[a -> b] -- IO List of functions
param :: IO[a] -- Single parameter
and I want to get
result :: IO[b]
result = IO[*first function* <$> param, *second function* <$> param, ...]
I somehow could get result of type IO[IO b]
, but I want IO[b]
Upvotes: 1
Views: 92
Reputation: 74244
By "single parameter" I assume you mean a one element list. If so, then here's how it's done:
result :: IO [b]
result = do
fs <- functions -- fs :: [a -> b]
xs <- param -- xs :: [a]
let ys = fs <*> xs -- ys :: [b]
return ys
Note that since xs
is a one element list you're essentially applying every element of fs
to that value.
This is the same as:
import Control.Applicative (liftA2)
result :: IO [b]
result = liftA2 (<*>) functions param
Hope that helps.
Upvotes: 7
Reputation: 22433
This looks very much like a simple <*>
, but we need to call it... deeply. Can we do this using only the Applicative
instance, without resorting to Monad
?
Solving a simpler problem first:
functions :: IO (a -> b)
param :: IO a
We could use:
functions <*> param
To get an IO b
.
Similarly, given a list of functions and a list of values:
functions :: [a -> b]
param :: [a]
We could use:
functions <*> param
To get a [b]
.
But now to do both at the same time:
functions :: IO [a -> b]
param :: IO [a]
This is... trickier, because we'll have to take advantage of the Applicative
instance for IO
and the Applicative
instance for []
at the same time. But it's still doable:
doubleAp fns x = liftedFns <*> x
where apList = (<*>) :: [a -> b] -> [a] -> [b]
liftedFns = fmap apList fns :: IO ([a] -> [b])
Or the more concise but harder (for me) to parse:
doubleAp fns x = ((<*>) <$> fns) <*> x
Or, according to blunt:
doublAp = (<*>) . ((<*>) <$>)
Upvotes: 4
Reputation: 18075
sequence
will get you from [IO b]
to IO [b]
, join
will get you from IO (IO [b])
to IO [b]
.
Upvotes: 3