Apply the composition of a list of functions to each number of a list

Given a list of functions and a list of numbers, I want first function to be applied to a list of numbers, the result then used for second function, and so on.

wantedFunc [(*2), (+2), (/2)] [1,2,3,4]
              |     |     |
              |     |     |
              V     |     |
        [2,4,6,8]---|     |
                    |     |
                    V     |
             [4,6,8,10]---|
                          V 
                      [2,3,4,5] -- End result

Is there a build-in function for this?

Upvotes: 3

Views: 287

Answers (6)

josejuan
josejuan

Reputation: 9566

Applying directly your definition we get

wantedFunc :: [(a -> a)] -> [a] -> [a]
wantedFunc fs xs = foldl (\ys f -> map f ys) xs fs

but we can transform

foldl (\ys f -> map f ys) xs fs
foldl (\ys f -> flip map ys f) xs fs    -- flip map
foldl (flip map) xs fs                  -- remove lambda
flip (foldl (flip map)) fs xs           -- flip foldl
flip (foldl (flip map))                 -- remove lambda
flip $ foldl $ flip map                 -- or using ($)

and finally

wantedFunc :: [(a -> a)] -> [a] -> [a]
wantedFunc = flip $ foldl $ flip map

on the other hand we can change the function signature flipping arguments and the functions list order and we can write that function as

wantedFunc' :: [a] -> [(a -> a)] -> [a]
wantedFunc' = foldr map

e.g.

main = do
    print $ wantedFunc  [(*2), (+2), (/2)] [1,2,3,4]
    print $ wantedFunc' [1,2,3,4] [(/2), (+2), (*2)]

with output

[2.0,3.0,4.0,5.0]
[2.0,3.0,4.0,5.0]

Upvotes: 1

Free_D
Free_D

Reputation: 577

Just compose all the functions and apply map.

wantedFunc :: [a->a] -> [a] -> [a]
wantedFunc fs = map (foldl1 (.) fs)

Upvotes: 1

karakfa
karakfa

Reputation: 67467

a one-liner solution can be

> map (foldr (.) id $ reverse [(*2),(+2),(/2)]) [1..4]
[2.0,3.0,4.0,5.0]

Upvotes: 1

behzad.nouri
behzad.nouri

Reputation: 77951

A right fold solution would be:

fun :: (Functor f, Foldable t) => t (a -> a) -> f a -> f a
fun = foldr (\f -> (. fmap f)) id

then,

\> fun [(*2), (+2)] [1,2,3,4]
[4,6,8,10]

\> fun [(*2), (+2), (`div` 2)] [1,2,3,4]
[2,3,4,5]

Upvotes: 2

user2297560
user2297560

Reputation: 2983

Here's a fmap fmap approach, using a Monoid to compose the functions.

newtype Endo a = Endo { unwrap :: a -> a }

instance Monoid (Endo a) where
  mempty = Endo id
  mappend (Endo f) (Endo g) = Endo (g . f)

wantedFunc = unwrap . mconcat . fmap (Endo . fmap)

λ wantedFunc [(*2), (+2), (/2)] [1,2,3,4]
[2.0,3.0,4.0,5.0]

Upvotes: 1

jub0bs
jub0bs

Reputation: 66234

Something like

import Control.Arrow ((>>>))

wantedFunc :: Foldable t => t (a -> a) -> [a] -> [a]
wantedFunc fs = map f
  where
    f = compose fs
    compose = foldr (>>>) id

does the trick:

λ> wantedFunc [(*2), (+2), (/2)] [1, 2, 3, 4]
[2.0,3.0,4.0,5.0]

Upvotes: 3

Related Questions