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#
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
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();<span style="color: blue;">var</span> foo = container.Get<IFoo>(); <span style="color: blue;">var</span> 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());
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 * Explet 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
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());