Skip to content

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.

Notifications You must be signed in to change notification settings

holoed/FunctionalCSharp

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

32 Commits
 
 
 
 
 
 

Repository files navigation

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();
        <span style="color: blue;">var</span> foo = container.Get&lt;IFoo&gt;();
        <span style="color: blue;">var</span> bar = container.Get&lt;IBar&gt;();


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());

About

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.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published