Click here to Skip to main content
Click here to Skip to main content

Functional Programming in C# 3.0 using Lambda Expression - Part 2

, 21 Feb 2009
Rate this:
Please Sign up or sign in to vote.
This article explains how to use C# 3.0 lambda expression & LINQ for functional programming

Introduction

In Part 1 of this article, we have seen that the two of eight functional factors are satisfied in C# 3.0 using generic and lambda expression. In this article, let us see how does C# 3.0 satisfy remaining factors:

  1. Anonymous function name (proved)
  2. Type inference (proved)
  3. Parameterized types
  4. High order functions
  5. Immutable data structure
  6. Recursion
  7. Currying
  8. Lazy evalution

Generic Lambda Expression - contd.

Part 1 of this article, we have seen Func and Action provide very lighter syntax which avoid the need to declare a Delegate type for a lambda expression. Code 1 shows the usage of Func.

// Code 1
// Generic Lambda Expression Usage
Func<int, int> Square = x => x * x;
int result = Square(4);
Console.WriteLine(result); // 16

Delegate type declaration is not necessary when using generic lambda expression. In Code 1, you can see that Func<int, int> Square provides parameterized type for the expression x => x * x;. This enables the C# compiler to infer the type detail of x. Note that delegate type declaration also provides type details to C# compiler, however this syntax improves developer productivity. This satisfies factor #3 Parameterized types. Let us see one more example (Code 2) using generic lambda expression which satisfies next two functional factors.

// Code 2
// Generic Lambda Expression Usage
List<int> primes = new List<int>();
List<int> primeCubes = new List<int>();

// adding set of values to primes
primes.Add(2); primes.Add(3); primes.Add(5); primes.Add(7);

// iterate through primes elements and calculate cube and
// add it to primeCubes using Action<int> action
primes.ForEach(x => primeCubes.Add(x * x * x));

foreach (int i in primeCubes)
{
    Console.WriteLine(i);
}

ForEach in .NET 3.5 generic collection requires Action<T> type, here Action<int>. The line primes.ForEach(x => primeCubes.Add(x * x * x)); shows how C# 3.0 allows you to easily pass a method as an argument to a method. Here x => primeCubes.Add(x * x * x) function is passed as argument. This proves that C# 3.0 satisfies functional factor #4 high order function. In this example, you can also see the immutability nature of .NET 2.0's collection types so that I have used one more List<int> type primeCubes. This behaviour proves the functional factor #5 immutability data structure.

Let us see one more example (Code 3) using generic lambda expression.

// Code 3
// Generic lambda expression usage
// declare a parameterized type XPowerN
Func<int, float, float> XPowerN = null;

// definition
XPowerN = (n, x) =>
    {
        if (n == 0) return 1.0f;
        else return x * XPowerN(n - 1, x);
    };

// using XPowerN in Square & Cube methods
Func<float, float> Square = x => XPowerN(2, x);
Func<float, float> Cube = x => XPowerN(3, x);

Console.WriteLine(Square(5.0f).ToString());
Console.WriteLine(Cube(5.0f).ToString());

In this example, you can see that the method XPowerN requires n and x of type int and float respectively as arguments and it calculates xn by calling itself recursively. This proves functional factor #6 recursion.

Note: In Code 3, you cannot declare the method XPowerN like the following:
// The following code throws "use of unassigned local variable XPowerN" error.
Func<int, float, float> XPowerN = (n, x) =>
{
    if (n == 0) return 1.0f;
    else return x * XPowerN(n - 1, x);
};

There are other ways to resolve this issue, however, I am comfortable with the approach shown in Code 3.

In code 3, Square and Cube methds use XPowerN method with n value as 2 and 3 respectively. The return value of these methods are the return value of XPowerN. This proves functional factor #7 currying.

Expression Tree

In addition to lambda expression, .NET 3.5 introduces expression tree which is a data structure generally used to represent an expression. In the tree, nodes contain either operands and operators. For example, the expression 3 + (5 + 9) * 2 can be represented as expression tree as shown in the following figure.

Expression Tree

Let us see an example (Code 4) to calculate volume of a cylinder (v = πr2h, where r is radius and h is height) using expression tree.

Cylinder
// Code 4
// Cylinder volume using lambda expression and
// expression tree

// Using lambda expression
Func<double, double, double> CylinderVolume = 
        (r, h) => 3.14 * r * r * h;
CylinderVolume(3, 9); // invoking the expression

// Using expression tree
Expression<Func<double, double, double>> XTCylinderVolume = 
        (r, h) => 3.14 * r * r * h;
XTCylinderVolume.Compile()(3, 9); // just compiling and invoke.

When you see the IL equivalent code for expression tree, the compiler emits an expression tree that represents lambda expression. See code 5.

// Code 5
// IL code for expression tree example shown in Code 4
private static void Main(string[] args)
{
    ParameterExpression CS$0$0000;
    ParameterExpression CS$0$0001;
    Expression<Func<double, double, double>> 
  XTCylinderVolume = Expression.Lambda<Func<double, double, double>>
  (Expression.Multiply(
  Expression.Multiply(
  Expression.Multiply(Expression.Constant(3.14, typeof(double)), 
  CS$0$0000 = Expression.Parameter(typeof(double), "r")), CS$0$0000), 
  CS$0$0001 = Expression.Parameter(typeof(double), "h")), 
  new ParameterExpression[] { CS$0$0000, CS$0$0001 });
}

In code 4, the only difference between lambda and expression tree is Expression<T>. The compiler emits respective expression types (operators and operands) in IL as shown in code 5. In code 4, the line XTCylinderVolume.Compile()(3, 9); tells the compiler that compile the expression but delay the evaluaion till invoked. The Compile method actually compiles the code represented by the expression tree into an executable delegate. This executable code is equivalent to the executable code that would have been generated had the lambda expression been assigned to a delegate type originally. This is called as lazy evaluation means that the expression will be evaluated only at the invocation, that is only at (3,9). Lazy evaluation is actually the functional factor #8.

Based on the above, we can strongly say C# 3.0 is a functional programming language too. Moreover, LINQ in .NET 3.5 really uses the above to enable the developers to write code which use both procedural and functional whereever suitable. Lazy evaluation is one of the major advantage of LINQ. The following figure shows the building blocks of LINQ

LINQ

In the above figure, you can see that lambda expression and expression tree are two fundamental building block of LINQ. Code 6 shows the usage of LINQ with these features:

// Code 6
// LINQ usage
class Movie
{
    public string Title { get; set; }
    public double Rating { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        // movies list created with set of values
        List<Movie> movies = new List<Movie>
        {
            new Movie { Title="The Dark Knight", Rating= 4.5},
            new Movie { Title="Wall-E", Rating= 2.0},
            new Movie { Title="Hancock", Rating= 1.0}
        };

        // LINQ expression
        var bestRatedMovies = from m in movies
                              where m.Rating >= 3.0
                              select m;

        // after the expression
        // two more movies added to the movies list
        movies.AddRange(
            new List<Movie>
        {
          new Movie { Title="Slumdog Millionaire", Rating= 5.0},
          new Movie { Title="Kung Fu Panda", Rating= 3.0}
        });

        // this evaluates latest movies too
        // lazy evaluation happends here 
        foreach (var m in bestRatedMovies)
        {
            Console.WriteLine("{0}\t{1}", m.Title, m.Rating);
        }
        Console.ReadLine();
    }
}

References

You can download and see my two part screen cast about Functional Programming using C# 3.0 from my skydrive http://cid-1ea86c1fb1c134b8.skydrive.live.com/browse.aspx/ScreenCast

License

This article, along with any associated source code and files, is licensed under The Creative Commons Attribution-ShareAlike 2.5 License

About the Author

M Sheik Uduman Ali
Architect Aditi
India India
Working as Architect for Aditi, Chennai, India.
 
My Website: www.udooz.net
 
My Blog: www.udooz.net/blog
Follow on   Twitter

Comments and Discussions

 
GeneralMy vote of 5 PinmemberNandu0914-Mar-11 5:19 
GeneralOutstanding article series! PinmemberAre Jay25-Jan-10 19:32 
GeneralNice article Pinmemberazweepay17-Feb-09 20:44 
GeneralRe: Nice article PinmemberM Sheik Uduman Ali18-Feb-09 1:54 
AnswerCylinder Volume PinmemberTobiasP18-Feb-09 2:29 
Actually, assuming r is the radius and h is the height, you are both wrong. Smile | :)
 
The correct calculation of the volume would be Math.PI * r * r * h, with the radius do used twice, but multiplied with the height instead of divided by two. Smile | :)
GeneralRe: Cylinder Volume PinmemberM Sheik Uduman Ali21-Feb-09 2:41 
GeneralRe: Nice article Pinmemberjszczur18-Feb-09 4:06 
GeneralRe: Nice article PinmemberM Sheik Uduman Ali18-Feb-09 17:55 
AnswerRe: Nice article PinmemberADLER122-Feb-09 1:20 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140718.1 | Last Updated 21 Feb 2009
Article Copyright 2009 by M Sheik Uduman Ali
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid