Skip to content

Instantly share code, notes, and snippets.

@jpablo
Last active July 18, 2020 21:33
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jpablo/4fc1b94015f6c55c2b8bff66ab17eb50 to your computer and use it in GitHub Desktop.
Save jpablo/4fc1b94015f6c55c2b8bff66ab17eb50 to your computer and use it in GitHub Desktop.
Extensibility for the masses, typescript:
// Initial object algebra interface for expressions: integers and addition
interface ExpAlg<E> {
lit(x: number): E
add(e1: E, e2: E): E
}
// The evaluation interface
interface Eval {
eval(): number
}
// The object algebra
class EvalExpAlg implements ExpAlg<Eval> {
lit(x: number) {
return {eval: () => x}
}
add(e1: Eval, e2: Eval) {
return {
eval: () => e1.eval() + e2.eval()
}
}
}
// Evolution 1: Adding subtraction
interface SubExpAlg<E> extends ExpAlg<E> {
sub(e1: E, e2: E): E
}
// Updating evaluation:
class EvalSubExpAlg extends EvalExpAlg implements SubExpAlg<Eval> {
sub(e1: Eval, e2: Eval) {
return {
eval: () => e1.eval() - e2.eval()
}
}
}
// Evolution 2: Adding pretty printing
interface PPrint {
print(): string;
}
class PrintExpAlg implements SubExpAlg<PPrint> {
lit(x : number) {
return {
print: () => x.toString()
}
}
add(e1 : PPrint, e2 : PPrint) {
return {
print: () => e1.print() + " + " + e2.print()
}
}
sub(e1 : PPrint, e2 : PPrint) {
return {
print: () => e1.print() + " - " + e2.print()
}
}
}
// 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 implements SubExpAlg<String> {
lit(x : number) { return x.toString() }
add(e1 : string, e2 : string) { return e1 + " + " + e2 }
sub(e1 : string, e2 : string) { return e1 + " - " + e2 }
}
// Testing
function exp1<E>(alg: ExpAlg<E>) {
return alg.add(alg.lit(3), alg.lit(4))
}
function exp2<E>(alg: SubExpAlg<E>) {
return alg.sub(exp1(alg), alg.lit(4))
}
const ea = new EvalExpAlg();
const esa = new EvalSubExpAlg();
const ev = exp1(esa);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment