Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a name for a function that takes a piece of data and a list of functions and applies each function to the result of the last one?

Clojure has a macro, ->, which takes a piece of data and a bunch of functions, applies the data to the first function, and then applies the result of that to the next one, the result of that to the third one, and so on, finally giving you back the result of the last application.

I quite like this because instead of having to write functions backwards from the order in which they are applied, like so: (pseudo-code follows)

floor (square.root (x))

you can write them in the order that the data flows through them:

-> x (square.root, floor)

My question is, is there a standard name for this function in functional languages, in the way that map, reduce, and filter have standard names? The Clojure docs describe it as 'threading the data through the functions', but I couldn't find anything on googling the word thread. I wrote a simple version of it in Haskell:

thread :: a -> [(a -> a)] -> a
thread x []     = x
thread x (f:fs) = thread (f x) fs

and searched for a -> [(a -> a)] -> a on Hoogle, but that didn't come up with anything either.

While researching for this question I also gleaned that you can do a very similar thing using the function composition operators from Control.Arrow in Haskell, like so:

($2) (sin >>> cos >>> tan)

whereas using the dedicated higher-order thread function you would write:

thread 2 [sin, cos, tan]

Is it perhaps the case that the first formulation suffices for practical usage?

like image 839
Marius Kempe Avatar asked Mar 03 '12 11:03

Marius Kempe


3 Answers

The name you're looking for is function composition.

The difference between the threading macro and comp comes from the former leveraging Clojure homoiconicity, while the latter is more close to the mathematical definition of composition.

In facts, you can transform a threading macro call to a comp call if you create one function of one argument per step, and reverse the order of the functions:

(defn sin [n] (Math/sin n))
(defn cos [n] (Math/cos n))

(-> 1 sin cos sin cos cos) ; 0.6858966217219662
((comp cos cos sin cos sin) 1) ; 0.6858966217219662
like image 141
skuro Avatar answered Oct 20 '22 04:10

skuro


I think you can use foldl for this, using appropriate arguments:

-- functions for testing
f1 x = x+1
f2 x = x*2
f3 x = x*x
-- here comes the line you're interested in
foldl (\x y -> y x) 2 [f1, f2, f3]

The arguments are as follows:

  • (\x y -> y x) is a function taking a function y and applying it to the argument x. y will then be substituted by each function from the list.
  • 2 is the initial argument you want to give to the functions.
  • [f1, f2, f3] is the list of functions.

Using these arguments, foldl computes the following: f3(f2(f1(2))).

like image 4
phimuemue Avatar answered Oct 20 '22 05:10

phimuemue


Given that >>> is similar to bash shell's pipeline operator rooted from Unix, I would call it pipeline sequence combinator.

like image 2
pad Avatar answered Oct 20 '22 05:10

pad