Project Description

Simple Functional Programming Library for C#. It introduces several features found in programming languages like F#. It is built in a compositional fashion starting from Pattern Matching and building on that to support Object Expressions, Tuples, Active Patterns, ADTs.

Recommended Reading
Functional Programming for the Real World: With Examples in F# and C#

Pattern Matching

var Op = new Dictionary<ExpressionType, string> { { ExpressionType.Add, "+" } };

Expression<Func<int,int,int>> add = (x,y) => x + y;

Func<Expression, string> toString = null;
 toString = exp =>
 exp.Match()
    .With<LambdaExpression>(l => toString(l.Body))
    .With<ParameterExpression>(p => p.Name)
    .With<BinaryExpression>(b => String.Format("{0} {1} {2}", toString(b.Left), Op[b.NodeType], toString(b.Right)))
    .Return<string>();

F# Equivalent
let operator x = match x with
                 | ExpressionType.Add -> "+"

let rec toString exp = match exp with
                       | LambdaExpression(args, body) -> toString(body)
                       | ParameterExpression(name) -> name
                       | BinaryExpression(op,l,r) -> sprintf "%s %s %s" (toString l) (operator op) (toString r)


C# with Active Patterns
Func<Expression, string> toString = null;
toString = exp =>
           exp.Match()
              .Lambda((args, body) => toString(body))
              .Param ((name)       => name)
              .Add   ((l, r)       => String.Format("({0} + {1})", toString(l), toString(r)))
              .Mult  ((l, r)       => String.Format("{0} * {1}", toString(l), toString(r)))
              .Return<string>();

C# Arithmetic Pattern n+ k
Func<int, bool> even = null;
Func<int, bool> odd = null;
even = exp => exp.Match()
                 .With(n => 0,     _ => true)
                 .With(n => n + 1, n => odd(n))
                 .Return<bool>();
odd = exp => !even(exp);

Haskell equivalent
 even 0 = True
 even (n + 1) = odd n
 odd n = not (even n)


C# Lists Pattern Matching
Func<Func<char, char>, Func<IEnumerable<char>, IEnumerable<char>>> map = null;
map = f => s => s.Match()
                 .List((x, xs) => f(x).Cons(map(f)(xs)))
                 .Any(() => s)
                 .Return<IEnumerable<char>>();
var toUpper = map(Char.ToUpper);

F# Equivalent
let rec map f xs = match xs with
                   | x::xs -> f(x)::(map f xs)
                   | _ -> xs;;
let toUpper = map System.Char.ToUpper

Object Expressions

C#
var foo = ObjectExpression.New<IFoo>()
                          .With(o => o.A, () => "Hello")
                          .Return();
F# Equivalent
let foo = { new IFoo with
                member x.A () = "Hello" }

Sample IoC Container
            var container = ObjectExpression
                 .New<IoC_Container>()
                 .With(o => o.Get<IFoo>, () => ObjectExpression.New<IFoo>().Return())
                 .With(o => o.Get<IBar>, () => ObjectExpression.New<IBar>().Return())
                 .Return();

            var foo = container.Get<IFoo>();
            var bar = container.Get<IBar>();

Sorted List (Create an IComparer on the fly ;))
var list = new SortedList<int, string>(
                ObjectExpression
                .New<IComparer<int>>()
                .With(o => o.Compare, (int x, int y) => x - y)
                .Return());

C# Discriminated Unions

public interface Exp
{
   Exp Var(string x);
   Exp Lam(string x, Exp e);
   Exp Let(string x, Exp e1, Exp e2);
   Exp App(Exp e1, Exp e2);
}

var exp = DataType.New<Exp>();

exp = exp.Let("compose",
                            exp.Lam("f",
                                    exp.Lam("g",
                                            exp.Lam("x",
                                                    exp.App(exp.Var("g"), exp.App(exp.Var("f"), exp.Var("x")))))),
                            exp.Var("compose"));

Func<Exp, string> toString = null;
toString = expr => expr.Match()
    .With(o => o.Var, (string x) => x)
    .With(o => o.Let, (string x, Exp e1, Exp e2) => string.Format("let {0} = {1} in {2}", x, toString(e1), toString(e2)))
    .With(o => o.Lam, (string x, Exp e) => string.Format("fun {0} -> {1}", x, toString(e)))
    .With(o => o.App, (Exp e1, Exp e2) => string.Format("({0} {1})", toString(e1), toString(e2)))
    .Return<string>();

Assert.AreEqual("let compose = fun f -> fun g -> fun x -> (g (f x)) in compose", toString(exp));


F# Equivalent
type Exp = Var of string
         | Lam of string * Exp
         | Let of string * Exp * Exp
         | App of Exp * Exp

let composeAst = Let("compose",
                    Lam("f",
                        Lam("g",
                            Lam ("x",
                                App(Var "g", App(Var "f", Var "x"))))),
                        Var "compose")

let rec toString exp = 
    match exp with
    | Var x -> x
    | Let (x, e1, e2) -> String.Format("let {0} = {1} in {2}", x, toString(e1), toString(e2))
    | Lam (x, e) -> String.Format("fun {0} -> {1}", x, toString(e))
    | App (e1, e2) -> String.Format("({0} {1})", toString(e1), toString(e2))

let ret = toString composeAst

Monadic Parser

C#
public static IParser<IEnumerable<char>, IEnumerable<string>> String()
{
   return CharParser.Word()
                .AsString()
                .SepBy(CharParser.Whitespace()
                                 .Many1()
                                 .AsString());
}

CollectionAssert.AreEqual
                (new[] {"Welcome", "to", "the", "real", "world"},
                 StringParser.String().ParseString("Welcome to the real world").First());

Last edited Sep 9, 2010 at 1:55 PM by holoed, version 48