Composing multiple functions

Last post we looked at left-to-right function composition. One idea that cropped up while I was thinking about composition was how to compose an arbitrary number of functions, say, because we’re dealing with a list of them. For this case we want to convert a list of functions [a -> a] into a single, composed function a -> a.

One approach is to fold over the list, and apply the accumulated argument to each new function. Whether we choose fold left or right will depend on the order we want the functions composed. For example, [a, b, c] can be composed right-to-left as a . b . c, or left-to-right as c . b . a.

-- compose all functions left-to-right 
(|>>>) :: [a -> a] -> a -> a
fs |>>> input = foldl' (flip ($)) input fs
-- or for pointfree fans:
--    (|>>>) = flip . foldl' . flip $ ($)

-- compose all functions right-to-left 
(<<<|) :: [a -> a] -> a -> a
fs <<<| input = foldr ($) input fs
-- or: (<<<|) = flip (foldr ($))

We can then apply the String transformations we looked at last post.

ghci> let transforms = [reverse, (++ " world"), (++ "!")]
ghci> transforms |>>> "olleh"
"hello world!"
ghci> (reverse transforms) <<<| "olleh"
"hello world!"

I’m not sure if this is at all useful, but I found it interesting to think through. It also led to me looking at some of the maths behind this form of composition (which I’ll look at in a later post).

Comments