Monday, November 24, 2008

[2008.11.24] The Mario Brothers aren’t the only ones who can use pipes

Generally, we understand that f(x) means that f is a function and x is its argument. Therefore, the function acts on its argument.

In F#, not only can we represent functions in the traditional format, and usually the parenthesis surrounding the argument can be dropped, so f(x) becomes f x. However, we can also work with functions from the other direction, that is, function application in reverse, where f x = x f.

In order for this to work, we need an operator that understands what we are trying to accomplish and this is left to the pipe operator: |>. It allows you to chain a set of operations, executing each in turn.

#light

#r "FSharp.PowerPack.dll"

(*

Example1: Simple pipe-lining

*)

 

// instead of doing

List.map (fun x -> (x, x*x) ) [1;2;3;4]

val it : (int * int) list = [(1, 1); (2, 4); (3, 9); (4, 16)]

 

// we can do

[1;2;3;4] List.map (fun y -> (y ,y*y) // and get the same result

 

(*

Example2: Chaining

Imagine a list of random integers between 0 to 20 and you want to

perform a series of operations on the list such as subtracting

10 from each item and returning the sorted square root of each

positive number in the list

 

We can now introduce an algorithm to solve this problem. In C#,

for example, you may create functions to perform each step,

and then nest several function calls to get the desired result.

At some point, it begins to get messy and is sort of the

reverse of the way we think about the problem.

 

Here is just one way to walk through this using the pipe,

|>, operator

*)

 

//1. create a function that takes the number of items in

//  the list

let operations listLength =

    let random = new System.Random()

    // 2. create a list of random numbers from 0 to 20

    let randomIntList = List.init listLength

                            (fun x -> random.Next(20))

    randomIntList // the left operator to |>

        // 3. subtract 10

        |> List.map    ( fun x -> x - 10 )

        // 4. filter out all negative #s

        |> List.filter  ( fun x -> x > -1 )

        // 5. convert integer to floats

        |> List.map    ( fun x -> float x)

        // 6. do squareroot

        |> List.map    ( fun x -> System.Math.Sqrt(x) )

        // 7. sort list

        |> List.sort compare                              

 

// the signature of the operations function is as follows:

val operations : int -> float list

 

// call our function and see the results 

let res = operations 20

val it : float list

= [0.0; 1.0; 1.0; 1.414213562; 1.732050808; 2.236067977;

    2.236067977; 2.645751311; 2.645751311; 3.0]