KEMBAR78
Let Us Learn Lambda Using C# 3.0 | PPS
M Sheik Uduman Ali Technical Lead iSOFT Plc [email_address] Let Us Learn
Procedural Programming int i = 0; i = i + 10; Output is deterministic  σ ΄ = f( σ ) Modifying the values of variables –  state σ  =  σ 0     σ 1     σ 2    …  σ n  =  σ  Sequential, conditional and repeated expression
Functional Programming Recursive functions – sequence is meaningless Variables are actually values // Procedural int Sum(int from, int to) { int result = 0; for(int i = from; i <= to; i++) result += i; return result; } // Recursive int Sum(int from, int to) { if(from > to) return 0; int result = Sum(from + 1, to); return from + result; }
Functional Programming Functions as values  Treated as simple objects like “Integer” can be passed as arguments, returned as results and  calculated with others High order functions Curried functions Immutable data structure MyList l0 = new MyList(); MyList l1 = l0.Add(100); MyList l2 = l1.Add(101); MyList result = l2.Add(102); MyList result = new MyList().Add(100).Add(101).Add(102); No assignments
Procedural: So What? No side-effect on expression evaluation More corresponds to mathematics Code can be more general problem solving by denotational semantics sub expression can be evaluated in any order parameterized
Code Comparison C int factorial(n) { int x = 1; while (n > 0) { x = x * n; n = n - 1; } return x; } F# let rec factorial num = match num with | n when n <= 1 -> 1 | n -> n * (factorial (n - 1)) fact(n) =    n! if n    0,      otherwise
A Debate Procedural:  I can use function pointers to treat “function as objects” Functional:  but you can’t create functions dynamically, and your function pointers are very limited. Procedural:  Me too support recursive..! Functional:  agreed. but everything is command driven as like as human approaches the computer.
A Debate Procedural:  What's in denotational semantics?  Functional:  for you, state based. It is changed from input to output. may fail to terminate, for example, while(true) {x=x;}.  alternative  predicate transformers are  goto, break and continue Procedural:  What's the benefit of “any order expression evaluation”? Functional:  I can do parallel programming simpler way
FP: Advantages  Shorter order of magnitude O(n) No assignments. Procedural programs consists 90% assignment statement Real modular programming Divide and conquer  No  goto  and  break .
Need for Lambda Calculus But in high order functions, insistence on naming is rather inconsistent, for example Define x and y by x = 2 and y = 4. Then xx = y Lambda notation allows to denote functions without naming  λx.t[x] for example,  λ x.x + 1  λ x.x 2 function argument fn. body
Lambda Calculus: Basic t is a lambda expression, if t = x where x    Var t =  λ x. M where x    Var and M is lambda expression t = MN where M and N are lambda expression  Three types of lambda expression: variables (referencing lambda expression) lambda abstractions (defining functions) applications (invoking functions)
Lambda Calculus: Basic In the expression  λ x.xy, x is bound variable (fall within the scope of  λ ) y is free variable (take the value from expression) Using lambda notation, traditional  f(x)  can be written as  f x . i.e. left association f x y  means  ( f ( x ) ) ( y )    λ x. λ y.t[x,y]  can be written as   λ x y.t[x,y] currying
Lambda Calculus Adoption Anonymous function name Type inference Parameterized types High order functions Immutability Recursion Currying Lazy evaluation
Lambda Calculus in .NET
Delegates Introduced in C# 1.0, much improved in C# 2.0  Dynamically wire up a method caller to its target method Two aspects: type and instance. delegate int Transformer(int x); static void Main(string[] args) { Transformer t = Square; int result = t(3); Console.WriteLine(result); Console.ReadLine(); } static int Square(int x) {return x * x;} type instance actually Transformer t = new Transformer(Square)
Anonymous Methods Introduced in C# 2.0 Define methods without name by delegate Compiler does closure-conversion  delegate int Transformer(int x); static void Main(string[] args) { Transformer t = delegate(int x) { return x * x; }; int result = t(3); Console.WriteLine(result); Console.ReadLine(); } LC1: Anonymous Function Name private static Transformer CS$<>9__CachedAnonymousMethodDelegate1; private static int <Main>b__0(int x) { return (x * x); } Compiler generated
Generics Introduced in C# 2.0, emphasized in C# 3.0 Way of reusability with a template Improved type safety  Reduce casting and boxing IEnumerable<int> myints =  new List<int> { 1, 1, 2, 3, 5, 8, 11 }; foreach (int i in myints) Console.Write(&quot;{0}\t&quot;, i);
Lambda Expression C# 3.0’s anonymous method Anonymous method written in place of a delegate instance. delegate int Transformer(int x); static void Main(string[] args) { Transformer t = x => return x * x; int result = t(3); Console.WriteLine(result); Console.ReadLine(); } Lighter syntax Implicit typed parameters LC2: Type inference
Generic Lambda Expression Very lighter syntax  For methods of any return type and any reasonable number of arguments. delegate TResult X <T>  (  ); delegate TResult X <T,TResult>  (T1 arg1); delegate TResult X <T1,T2,TResult>  (T1 arg1, T2 arg2); delegate TResult X <T1,T2,T3,..Tn,TResult> (T1 arg1, T2 arg2,  T3 arg3,...,Tn argn); Func<int, int> t = x => x * x; int result = t(4); Console.WriteLine(result); Console.ReadLine(); LC3: Parameterized type Func | Action
Generic Lambda Expression 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); } LC4: High Order Function LC5: Immutability
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()); LC7: Currying LC6: Recursion
Expression Tree A data structure represents an expression Nodes as operands and operators 3 + (5 + 9) * 2 + 3 * + 5 9 2
Expression Tree Func<double, double, double> CylinderVolume =  (r, h) => 3.14 * r * r / 2; CylinderVolume(3, 9); Expression<Func<double, double, double>> XTCylinderVolume =  (r, h) => 3.14 * r * r / 2; XTCylinderVolume.Compile()(3, 9); Volume of a cylinder V =    radius 2  x height
IL Code for Delegate Lambda [CompilerGenerated] private static double <Main>b__0(double r, double h) { return (((3.14 * r) * r) / 2.0); } [CompilerGenerated] private static Func<double, double, double>  CS$<>9__CachedAnonymousMethodDelegate1; private static void Main(string[] args) { Func<double, double, double> CylinderVolume = delegate (double r, double h) { return ((3.14 * r) * r) / 2.0; }; }
IL Code for Expression Tree 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.Divide(Expression.Multiply(Expression.Multiply(Expression.Constant(3.14, typeof(double)), CS$0$0000 = Expression.Parameter(typeof(double), &quot;radius&quot;)), CS$0$0001 = Expression.Parameter(typeof(double), &quot;height&quot;)), Expression.Constant(2.0, typeof(double))), new ParameterExpression[] { CS$0$0000, CS$0$0001 }); }
Expression Tree Func<double, double, double> CylinderVolume =  (r, h) => 3.14 * r * r / 2; CylinderVolume(3, 9); Expression<Func<double, double, double>> XTCylinderVolume =  (r, h) => 3.14 * r * r / 2; XTCylinderVolume.Compile()(3, 9); LC8: Lazy Evaluation Volume of a cylinder V =    radius 2  x height
Expression Tree Func<double, double, double> CylinderVolume =  (r, h) => 3.14 * r * r / 2; CylinderVolume(3, 9); Expression<Func<double, double, double>> XTCylinderVolume =  (r, h) => 3.14 * r * r / 2; XTCylinderVolume.Compile()(3, 9); LC8: Lazy Evaluation Volume of a cylinder V =    radius 2  x height
LINQ
LINQ Sample
Questions?

Let Us Learn Lambda Using C# 3.0

  • 1.
    M Sheik UdumanAli Technical Lead iSOFT Plc [email_address] Let Us Learn
  • 2.
    Procedural Programming inti = 0; i = i + 10; Output is deterministic σ ΄ = f( σ ) Modifying the values of variables – state σ = σ 0  σ 1  σ 2  … σ n = σ  Sequential, conditional and repeated expression
  • 3.
    Functional Programming Recursivefunctions – sequence is meaningless Variables are actually values // Procedural int Sum(int from, int to) { int result = 0; for(int i = from; i <= to; i++) result += i; return result; } // Recursive int Sum(int from, int to) { if(from > to) return 0; int result = Sum(from + 1, to); return from + result; }
  • 4.
    Functional Programming Functionsas values Treated as simple objects like “Integer” can be passed as arguments, returned as results and calculated with others High order functions Curried functions Immutable data structure MyList l0 = new MyList(); MyList l1 = l0.Add(100); MyList l2 = l1.Add(101); MyList result = l2.Add(102); MyList result = new MyList().Add(100).Add(101).Add(102); No assignments
  • 5.
    Procedural: So What?No side-effect on expression evaluation More corresponds to mathematics Code can be more general problem solving by denotational semantics sub expression can be evaluated in any order parameterized
  • 6.
    Code Comparison Cint factorial(n) { int x = 1; while (n > 0) { x = x * n; n = n - 1; } return x; } F# let rec factorial num = match num with | n when n <= 1 -> 1 | n -> n * (factorial (n - 1)) fact(n) = n! if n  0,  otherwise
  • 7.
    A Debate Procedural: I can use function pointers to treat “function as objects” Functional: but you can’t create functions dynamically, and your function pointers are very limited. Procedural: Me too support recursive..! Functional: agreed. but everything is command driven as like as human approaches the computer.
  • 8.
    A Debate Procedural: What's in denotational semantics? Functional: for you, state based. It is changed from input to output. may fail to terminate, for example, while(true) {x=x;}. alternative predicate transformers are goto, break and continue Procedural: What's the benefit of “any order expression evaluation”? Functional: I can do parallel programming simpler way
  • 9.
    FP: Advantages Shorter order of magnitude O(n) No assignments. Procedural programs consists 90% assignment statement Real modular programming Divide and conquer No goto and break .
  • 10.
    Need for LambdaCalculus But in high order functions, insistence on naming is rather inconsistent, for example Define x and y by x = 2 and y = 4. Then xx = y Lambda notation allows to denote functions without naming λx.t[x] for example, λ x.x + 1 λ x.x 2 function argument fn. body
  • 11.
    Lambda Calculus: Basict is a lambda expression, if t = x where x  Var t = λ x. M where x  Var and M is lambda expression t = MN where M and N are lambda expression Three types of lambda expression: variables (referencing lambda expression) lambda abstractions (defining functions) applications (invoking functions)
  • 12.
    Lambda Calculus: BasicIn the expression λ x.xy, x is bound variable (fall within the scope of λ ) y is free variable (take the value from expression) Using lambda notation, traditional f(x) can be written as f x . i.e. left association f x y means ( f ( x ) ) ( y )  λ x. λ y.t[x,y] can be written as λ x y.t[x,y] currying
  • 13.
    Lambda Calculus AdoptionAnonymous function name Type inference Parameterized types High order functions Immutability Recursion Currying Lazy evaluation
  • 14.
  • 15.
    Delegates Introduced inC# 1.0, much improved in C# 2.0 Dynamically wire up a method caller to its target method Two aspects: type and instance. delegate int Transformer(int x); static void Main(string[] args) { Transformer t = Square; int result = t(3); Console.WriteLine(result); Console.ReadLine(); } static int Square(int x) {return x * x;} type instance actually Transformer t = new Transformer(Square)
  • 16.
    Anonymous Methods Introducedin C# 2.0 Define methods without name by delegate Compiler does closure-conversion delegate int Transformer(int x); static void Main(string[] args) { Transformer t = delegate(int x) { return x * x; }; int result = t(3); Console.WriteLine(result); Console.ReadLine(); } LC1: Anonymous Function Name private static Transformer CS$<>9__CachedAnonymousMethodDelegate1; private static int <Main>b__0(int x) { return (x * x); } Compiler generated
  • 17.
    Generics Introduced inC# 2.0, emphasized in C# 3.0 Way of reusability with a template Improved type safety Reduce casting and boxing IEnumerable<int> myints = new List<int> { 1, 1, 2, 3, 5, 8, 11 }; foreach (int i in myints) Console.Write(&quot;{0}\t&quot;, i);
  • 18.
    Lambda Expression C#3.0’s anonymous method Anonymous method written in place of a delegate instance. delegate int Transformer(int x); static void Main(string[] args) { Transformer t = x => return x * x; int result = t(3); Console.WriteLine(result); Console.ReadLine(); } Lighter syntax Implicit typed parameters LC2: Type inference
  • 19.
    Generic Lambda ExpressionVery lighter syntax For methods of any return type and any reasonable number of arguments. delegate TResult X <T> ( ); delegate TResult X <T,TResult> (T1 arg1); delegate TResult X <T1,T2,TResult> (T1 arg1, T2 arg2); delegate TResult X <T1,T2,T3,..Tn,TResult> (T1 arg1, T2 arg2, T3 arg3,...,Tn argn); Func<int, int> t = x => x * x; int result = t(4); Console.WriteLine(result); Console.ReadLine(); LC3: Parameterized type Func | Action
  • 20.
    Generic Lambda ExpressionList<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); } LC4: High Order Function LC5: Immutability
  • 21.
    Generic Lambda ExpressionFunc<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()); LC7: Currying LC6: Recursion
  • 22.
    Expression Tree Adata structure represents an expression Nodes as operands and operators 3 + (5 + 9) * 2 + 3 * + 5 9 2
  • 23.
    Expression Tree Func<double,double, double> CylinderVolume = (r, h) => 3.14 * r * r / 2; CylinderVolume(3, 9); Expression<Func<double, double, double>> XTCylinderVolume = (r, h) => 3.14 * r * r / 2; XTCylinderVolume.Compile()(3, 9); Volume of a cylinder V =  radius 2 x height
  • 24.
    IL Code forDelegate Lambda [CompilerGenerated] private static double <Main>b__0(double r, double h) { return (((3.14 * r) * r) / 2.0); } [CompilerGenerated] private static Func<double, double, double> CS$<>9__CachedAnonymousMethodDelegate1; private static void Main(string[] args) { Func<double, double, double> CylinderVolume = delegate (double r, double h) { return ((3.14 * r) * r) / 2.0; }; }
  • 25.
    IL Code forExpression Tree 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.Divide(Expression.Multiply(Expression.Multiply(Expression.Constant(3.14, typeof(double)), CS$0$0000 = Expression.Parameter(typeof(double), &quot;radius&quot;)), CS$0$0001 = Expression.Parameter(typeof(double), &quot;height&quot;)), Expression.Constant(2.0, typeof(double))), new ParameterExpression[] { CS$0$0000, CS$0$0001 }); }
  • 26.
    Expression Tree Func<double,double, double> CylinderVolume = (r, h) => 3.14 * r * r / 2; CylinderVolume(3, 9); Expression<Func<double, double, double>> XTCylinderVolume = (r, h) => 3.14 * r * r / 2; XTCylinderVolume.Compile()(3, 9); LC8: Lazy Evaluation Volume of a cylinder V =  radius 2 x height
  • 27.
    Expression Tree Func<double,double, double> CylinderVolume = (r, h) => 3.14 * r * r / 2; CylinderVolume(3, 9); Expression<Func<double, double, double>> XTCylinderVolume = (r, h) => 3.14 * r * r / 2; XTCylinderVolume.Compile()(3, 9); LC8: Lazy Evaluation Volume of a cylinder V =  radius 2 x height
  • 28.
  • 29.
  • 30.