public
Created

Solutions to the Expression Problem Using Object Algebras

  • Download Gist
ObjectAlgebra.cs
C#
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
using System;
using System.Globalization;
 
 
namespace OASample
{
// Initial object algebra interface for expressions: integers and addition
interface IExpAlg<E>
{
E Lit(int x);
E Add(E e1, E e2);
}
 
// ----------------------------------------------------------------------
// An object algebra implementing that interface (evaluation)
// ----------------------------------------------------------------------
 
// The evaluation interface
public class Evaluator
{
Func<int> f;
public Evaluator(Func<int> f)
{
this.f = f;
}
public int Eval()
{
return f();
}
}
 
// The object algebra
class EvalExpAlg : IExpAlg<Evaluator>
{
public Evaluator Lit(int x)
{
Func<int> f = () => x;
return new Evaluator(f);
}
 
public Evaluator Add(Evaluator e1, Evaluator e2)
{
Func<int> f = () => e1.Eval() + e2.Eval();
return new Evaluator(f);
}
}
 
// ----------------------------------------------------------------------
// Evolution 1: Adding subtraction
// ----------------------------------------------------------------------
 
interface ISubExpAlg<E> : IExpAlg<E>
{
E Sub(E e1, E e2);
}
 
// Updating evaluation:
class EvalSubExpAlg : EvalExpAlg, ISubExpAlg<Evaluator>
{
public Evaluator Sub(Evaluator e1, Evaluator e2)
{
Func<int> f = () => e1.Eval() - e2.Eval();
return new Evaluator(f);
}
}
 
// ----------------------------------------------------------------------
// Evolution 2: Adding pretty printing
// ----------------------------------------------------------------------
 
public class IPPrint
{
Func<string> f;
public IPPrint (Func<string> f)
{
this.f = f;
}
public string Print ()
{
return f();
}
}
 
class PrintExpAlg : ISubExpAlg<IPPrint>
{
public IPPrint Lit(int x)
{
Func<string> f = () => x.ToString(CultureInfo.InvariantCulture);
return new IPPrint(f);
}
 
public IPPrint Add(IPPrint e1, IPPrint e2)
{
Func<string> f = () => e1.Print() + " + " + e2.Print();
return new IPPrint(f);
}
 
public IPPrint Sub(IPPrint e1, IPPrint e2)
{
Func<string> f = () => e1.Print() + " - " + e2.Print();
return new IPPrint(f);
}
}
 
// An alternative object algebra for pretty printing:
 
// Often, when precise control over the invocation of
// methods is not needed, we can simplify object algebras.
// For example, here's an alternative implementation
// of pretty printing that directly computes a string:
class PrintExpAlg2 : ISubExpAlg<string>
{
public string Lit(int x)
{
return x.ToString(CultureInfo.InvariantCulture);
}
 
public string Add(string e1, string e2)
{
return e1 + " + " + e2;
}
 
public string Sub(string e1, string e2)
{
return e1 + " - " + e2;
}
}
 
// ----------------------------------------------------------------------
// Testing
// ----------------------------------------------------------------------
 
class Program
{
// An expression using the basic ExpAlg
private static E Exp1<E>(IExpAlg<E> alg)
{
return alg.Add(alg.Lit(3), alg.Lit(4));
}
 
// An expression using subtraction too
private static E Exp2<E>(ISubExpAlg<E> alg)
{
return alg.Sub(Exp1(alg), alg.Lit(4));
}
 
private static void Main()
{
// Some object algebras:
var ea = new EvalExpAlg();
var esa = new EvalSubExpAlg();
var pa = new PrintExpAlg();
var pa2 = new PrintExpAlg2();
 
// We can call esa with Exp1
var ev = Exp1(esa);
 
// But calling ea with Exp2 is an error
// var ev_bad = Exp2(ea);
 
// Testing the actual algebras
Console.WriteLine("Evaluation of Exp1 '{0}' is: {1}", Exp1(pa).Print(), ev.Eval());
Console.WriteLine("Evaluation of Exp2 '{0}' is: {1}", Exp2(pa).Print(), Exp2(esa).Eval());
Console.WriteLine("The alternative pretty printer works nicely too!{0}Exp1: {1}{0}Exp2: {2}",
Environment.NewLine, Exp1(pa2), Exp2(pa2));
}
}
}

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.