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:
Anonymous function name (proved) Type inference (proved) - Parameterized types
- High order functions
- Immutable data structure
- Recursion
- Currying
- 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
.
Func<int, int> Square = x => x * x;
int result = Square(4);
Console.WriteLine(result);
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.
List<int> primes = new List<int>();
List<int> primeCubes = new List<int>();
primes.Add(2); primes.Add(3); primes.Add(5); primes.Add(7);
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.
Func<int, float, float> XPowerN = null;
XPowerN = (n, x) =>
{
if (n == 0) return 1.0f;
else return x * XPowerN(n - 1, x);
};
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:
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.
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.
Func<double, double, double> CylinderVolume =
(r, h) => 3.14 * r * r * h;
CylinderVolume(3, 9);
Expression<Func<double, double, double>> XTCylinderVolume =
(r, h) => 3.14 * r * r * h;
XTCylinderVolume.Compile()(3, 9);
When you see the IL equivalent code for expression tree, the compiler emits an expression tree that represents lambda expression. See code 5.
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
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:
class Movie
{
public string Title { get; set; }
public double Rating { get; set; }
}
class Program
{
static void Main(string[] args)
{
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}
};
var bestRatedMovies = from m in movies
where m.Rating >= 3.0
select m;
movies.AddRange(
new List<Movie>
{
new Movie { Title="Slumdog Millionaire", Rating= 5.0},
new Movie { Title="Kung Fu Panda", Rating= 3.0}
});
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