Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

F# Function Composition with multiple input parameters

Tags:

f#

I am new to F# and I recently discovered the function composition operator >>

I understand the basic principle so that something like this is possible....

let Add1ToNum x = x +1
let Mul2ToNum y = y * 2
let FuncComp = Add1ToNum >> Mul2ToNum

However, how would one handle composition when you have several functions that have a varying number of input parameters... for instance I would like to be able to do the following...

let AddNums (x,y) = x+y
let MulNums (x,y) = x*y
let FuncComp = Add1 >> Mul2

Which obviously doesn't work because AddNums is returning an int, and MulNums is expecting a tuple.

Is there some form of syntax that allows me to accomplish this, or if I am wanting to use Function Composition do I have to always perform some sort of intermediary function to transform the values?

Anyone suggestions on this would be much appreciated.

like image 803
Mark Pearl Avatar asked Jul 10 '10 05:07

Mark Pearl


2 Answers

As Yin and codekaizen pointed out, you cannot compose the two functions to create a function that passes the input to the first one and then passes the output of this call to the second function (that is, using th >> operator). Using a diagram, you cannot do:

     +---------+    +---------+
 --->| AddNums |--->| MulNums |--->
     +---------+    +---------+

One option is to change the function and specify one of the parameters, so that the functions can be composed. The example by codekaizen uses this and could be also written like this (if you used currying instead of tupled parameters):

let AddNums x y = x + y  
let MulNums x y = x * y  
let FuncComp = (AddNums 1) >> (MulNums 2)

Another option for composing the functions is to create a function that takes several inputs, passes two numbers to the first function and then calls the second function with the result and another number from the original inputs. Using a diagram:

 -----------------\
 --->+---------+   \+---------+
 --->| AddNums |--->| MulNums |--->
     +---------+    +---------+

If you need something like that, then the best option is to write that directly, because this probably won't be a frequently repeated pattern. Directly, this is easy (using the curried variant):

let AddNums x y = x + y  
let MulNums x y = x * y  
let FuncComp x y z = AddNums z y |> (MulNums z)

If you wanted to write something like that more generally (or just for curiosity), you could write something like this (using the tupled version of functions this time). The &&& operator is inspired by Arrows:

let AddNums (x,y) = x + y 
let MulNums (x,y) = x * y  

let (&&&) f g (a, b) = (f a, g b)
let FuncComp = (AddNums &&& id) >> MulNums

// First two numbers are added, result is multiplied by the third one
FuncComp ((9, 12), 2) // Gives '42'
like image 103
Tomas Petricek Avatar answered Oct 22 '22 05:10

Tomas Petricek


Yet another option is to make stack->stack functions much like an RPN calculator. For example:

let bin f = function a :: b :: t -> f b a :: t
let add = bin (+)
let mul = bin (*)

And perhaps a function to push literals to the stack:

let lit n t = n :: t

Then it's pure composition:

> (lit 9 >> lit 12 >> add >> lit 2 >> mul) []
42

You could even add stack shuffling functions:

let drop = function _ :: t -> t
let dup  = function x :: t -> x :: x :: t
let swap = function x :: y :: t -> y :: x :: t

And do things like:

let square = dup >> mul
let cube = dup >> dup >> mul >> mul
let negate = lit -1 >> mul

Just an experiment in crazyness!

(See also http://blogs.msdn.com/b/ashleyf/archive/2011/04/21/programming-is-pointless.aspx)

like image 3
AshleyF Avatar answered Oct 22 '22 06:10

AshleyF