Savenkov Alexey
Savenkov Alexey

Reputation: 698

Applying IO [a -> b] to single parameter of type a

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

Answers (3)

Aadit M Shah
Aadit M Shah

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

Ian Henry
Ian Henry

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

Mirzhan Irkegulov
Mirzhan Irkegulov

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

Related Questions