Last active
July 18, 2020 21:33
-
-
Save jpablo/4fc1b94015f6c55c2b8bff66ab17eb50 to your computer and use it in GitHub Desktop.
Extensibility for the masses, typescript:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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