Function composition

Function composition is perhaps the most fundamental skill to be mastered by a functional programmer. However simple it may sound, this is about combining some functions into a more powerful combination. This may sound close to the higher-order functions I have covered earlier, and it is close indeed. Function composition is just concentrating upon building chains of function applications that allow more powerful data transformations from the bunch of less complicated ones.

Combinators

How exactly does the function composition take place if, by definition, the functions considered the basis for composition are just sort of black boxes that can only consume arguments and produce results? This is correct; functions, arguments, and the single operation of an application are all that's required for composition (remember minimizing the moving parts). Still, composition is performed by functions as well. The function that somehow applies just its parameters or values (some of them may be function values) in order to produce results without involving any external context is named combinator. There is an entire branch of applied math, that is, Combinatory logic (https://en.wikipedia.org/wiki/Combinatory_logic) that is concerned, in particular, with the learning of combinators. This may take very capricious forms; those of you who want to delve deeper, I recommend that you Google the idiot bird combinator string and follow the links.

The id combinator

The simplest representative of combinators is id. Entering (id);; into FSI reveals this function signature ('a -> 'a). In other words, this combinator takes any value and simply returns it without any transformation.

Forward pipe |>

This combinator is the workhorse of idiomatic F#. Entering (|>);; into FSI reveals this function signature ('a -> ('a -> 'b) ->'b). In other words, this combinator applies its second argument, which is a function ('a -> 'b), to its first argument 'a, yielding the result 'b.

Also, it may seem that the order cannot be that important; however, it is important indeed. One of the factors involved is type inference, which works better for the piped function composition (remember left to right).

Backward pipe <|

Entering (<|);; into FSI reveals this function signature: (('a -> 'b) -> 'a -> 'b). In other words, this combinator applies its first argument ('a -> 'b) to the second 'a, yielding the result 'b. At first glance, this combinator may seem excessive. However, an important case when it becomes useful is in eliminating the need for parentheses around the argument and improving the readability of the code in the end.

Forward composition >>

This combinator composes functions together. Entering (>>);; into FSI reveals this function signature (('a -> 'b) -> ('b -> 'c) -> 'a -> 'c). In other words, having two functions and an argument, it applies the first function to the argument and the second function to the result of the first application.

Backward composition 

This combinator composes functions together as well, but it does that differently. Entering (<<);; into FSI reveals this function signature (('a -> 'b) -> ('c -> 'a) -> 'c -> 'b). In other words, having two functions and an argument, it applies the second function to the argument and then the first function to the result of the first application. Sometimes, such an application order can be convenient for improved readability or other reasons.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset