Last active
August 29, 2015 14:24
-
-
Save xstpl/f5dd4a8f355f43992f83 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
// === step1 === | |
trait Pizza { | |
def remA: Pizza | |
} | |
case class Crust() extends Pizza { | |
def remA = Crust() | |
} | |
case class Cheese(p: Pizza) extends Pizza { | |
def remA = Cheese(p.remA) | |
} | |
case class Olive(p: Pizza) extends Pizza { | |
def remA = Olive(p.remA) | |
} | |
case class Anchovy(p: Pizza) extends Pizza { | |
def remA = p.remA | |
} | |
case class Sausage(p: Pizza) extends Pizza { | |
def remA = Sausage(p.remA) | |
} | |
Anchovy( | |
Olive( | |
Anchovy( | |
Anchovy( | |
Cheese( | |
Crust()))))) | |
.remA == | |
Olive( | |
Cheese( | |
Crust())) | |
Sausage( | |
Olive( | |
Anchovy( | |
Sausage( | |
Cheese( | |
Crust()))))) | |
.remA == | |
Sausage( | |
Olive( | |
Sausage( | |
Cheese( | |
Crust())))) | |
// === step2 === | |
trait Pizza { | |
def remA: Pizza | |
def topAwC: Pizza | |
} | |
case class Crust() extends Pizza { | |
def remA = Crust() | |
def topAwC = Crust() | |
} | |
case class Cheese(p: Pizza) extends Pizza { | |
def remA = Cheese(p.remA) | |
def topAwC = Cheese(p.topAwC) | |
} | |
case class Olive(p: Pizza) extends Pizza { | |
def remA = Olive(p.remA) | |
def topAwC = Olive(p.topAwC) | |
} | |
case class Anchovy(p: Pizza) extends Pizza { | |
def remA = p.remA | |
def topAwC = Cheese(Anchovy(p.topAwC)) | |
} | |
case class Sausage(p: Pizza) extends Pizza { | |
def remA = Sausage(p.remA) | |
def topAwC = Sausage(p.topAwC) | |
} | |
Olive(Anchovy(Cheese(Anchovy(Crust())))).topAwC == Olive(Cheese(Anchovy(Cheese(Cheese(Anchovy(Crust())))))) | |
Olive(Anchovy(Cheese(Anchovy(Crust())))).topAwC.remA == Olive(Cheese(Cheese(Cheese(Crust())))) | |
// === step3 === | |
trait Pizza { | |
def remA: Pizza | |
def topAwC: Pizza | |
def subAbC: Pizza | |
} | |
case class Crust() extends Pizza { | |
def remA = Crust() | |
def topAwC = Crust() | |
def subAbC = Crust() | |
} | |
case class Cheese(p: Pizza) extends Pizza { | |
def remA = Cheese(p.remA) | |
def topAwC = Cheese(p.topAwC) | |
def subAbC = Cheese(p.subAbC) | |
} | |
case class Olive(p: Pizza) extends Pizza { | |
def remA = Olive(p.remA) | |
def topAwC = Olive(p.topAwC) | |
def subAbC = Olive(p.subAbC) | |
} | |
case class Anchovy(p: Pizza) extends Pizza { | |
def remA = p.remA | |
def topAwC = Cheese(Anchovy(p.topAwC)) | |
def subAbC = Cheese(p.subAbC) | |
} | |
case class Sausage(p: Pizza) extends Pizza { | |
def remA = Sausage(p.remA) | |
def topAwC = Sausage(p.topAwC) | |
def subAbC = Sausage(p.subAbC) | |
} | |
Olive(Anchovy(Cheese(Anchovy(Crust())))).subAbC == Olive(Cheese(Cheese(Cheese(Crust())))) | |
// === step4 === | |
class OnlyOnions { | |
def forSkewer = true | |
def forOnion(s: Shish) = s.onlyOnions | |
def forLamb(s: Shish) = false | |
def forTomato(s: Shish) = false | |
} | |
trait Shish { | |
val ooFn = new OnlyOnions | |
def onlyOnions: Boolean | |
} | |
case class Skewer() extends Shish { | |
def onlyOnions = ooFn.forSkewer | |
} | |
case class Onion(s: Shish) extends Shish { | |
def onlyOnions = ooFn.forOnion(s) | |
} | |
case class Lamb(s: Shish) extends Shish { | |
def onlyOnions = ooFn.forLamb(s) | |
} | |
case class Tomato(s: Shish) extends Shish { | |
def onlyOnions = ooFn.forTomato(s) | |
} | |
Onion(Onion(Skewer())).onlyOnions should be (true) | |
// ==== step5 === | |
class OnlyOnions { | |
def forSkewer = true | |
def forOnion(s: Shish) = s.onlyOnions | |
def forLamb(s: Shish) = false | |
def forTomato(s: Shish) = false | |
} | |
class IsVegetarian { | |
def forSkewer = true | |
def forOnion(s: Shish) = s.isVegetarian | |
def forLamb(s: Shish) = false | |
def forTomato(s: Shish) = s.isVegetarian | |
} | |
trait Shish { | |
val ooFn = new OnlyOnions | |
val ivFn = new IsVegetarian | |
def onlyOnions: Boolean | |
def isVegetarian: Boolean | |
} | |
case class Skewer() extends Shish { | |
def onlyOnions = ooFn.forSkewer | |
def isVegetarian = ivFn.forSkewer | |
} | |
case class Onion(s: Shish) extends Shish { | |
def onlyOnions = ooFn.forOnion(s) | |
def isVegetarian = ivFn.forOnion(s) | |
} | |
case class Lamb(s: Shish) extends Shish { | |
def onlyOnions = ooFn.forLamb(s) | |
def isVegetarian = ivFn.forLamb(s) | |
} | |
case class Tomato(s: Shish) extends Shish { | |
def onlyOnions = ooFn.forTomato(s) | |
def isVegetarian = ivFn.forTomato(s) | |
} | |
Onion(Onion(Skewer())).onlyOnions should be (true) | |
Onion(Onion(Skewer())).isVegetarian should be (true) | |
// === step6 === | |
trait Pizza { | |
val remFn = new RemA | |
val topFn = new TopAwC | |
val subFn = new SubAbC | |
def remA: Pizza | |
def topAwC: Pizza | |
def subAbC: Pizza | |
} | |
case class Crust() extends Pizza { | |
def remA = remFn.forCrust | |
def topAwC = topFn.forCrust | |
def subAbC = subFn.forCrust | |
} | |
case class Cheese(p: Pizza) extends Pizza { | |
def remA = remFn.forCheese(p) | |
def topAwC = topFn.forCheese(p) | |
def subAbC = subFn.forCheese(p) | |
} | |
case class Olive(p: Pizza) extends Pizza { | |
def remA = remFn.forOlive(p) | |
def topAwC = topFn.forOlive(p) | |
def subAbC = subFn.forOlive(p) | |
} | |
case class Anchovy(p: Pizza) extends Pizza { | |
def remA = remFn.forAnchovy(p) | |
def topAwC = topFn.forAnchovy(p) | |
def subAbC = subFn.forAnchovy(p) | |
} | |
case class Sausage(p: Pizza) extends Pizza { | |
def remA = remFn.forSausage(p) | |
def topAwC = topFn.forSausage(p) | |
def subAbC = subFn.forSausage(p) | |
} | |
class RemA { | |
def forCrust: Pizza = Crust() | |
def forCheese(p: Pizza): Pizza = Cheese(p.remA) | |
def forOlive(p: Pizza): Pizza = Olive(p.remA) | |
def forAnchovy(p: Pizza): Pizza = p.remA | |
def forSausage(p: Pizza): Pizza = Sausage(p.remA) | |
} | |
class TopAwC { | |
def forCrust: Pizza = Crust() | |
def forCheese(p: Pizza): Pizza = Cheese(p.topAwC) | |
def forOlive(p: Pizza): Pizza = Olive(p.topAwC) | |
def forAnchovy(p: Pizza): Pizza = Cheese(Anchovy(p.topAwC)) | |
def forSausage(p: Pizza): Pizza = Sausage(p.topAwC) | |
} | |
class SubAbC { | |
def forCrust: Pizza = Crust() | |
def forCheese(p: Pizza): Pizza = Cheese(p.subAbC) | |
def forOlive(p: Pizza): Pizza = Olive(p.subAbC) | |
def forAnchovy(p: Pizza): Pizza = Cheese(p.subAbC) | |
def forSausage(p: Pizza): Pizza = Sausage(p.subAbC) | |
} | |
// == step7 === | |
trait Pie { | |
val remFn = new RemA | |
def remA: Pie | |
} | |
case class Bot() extends Pie { | |
def remA = remFn.forBot | |
} | |
case class Top(t: Object, r: Pie) extends Pie { | |
def remA = remFn.forTop(t, r) | |
} | |
trait Fish | |
case class Anchovy() extends Fish | |
case class Salmon() extends Fish | |
case class Tuna() extends Fish | |
class RemA { | |
def forBot: Pie = Bot() | |
def forTop(t: Object, r: Pie): Pie = if (Anchovy() == t) r.remA else Top(t, r.remA) | |
} | |
Top( | |
Salmon(), | |
Top( | |
Anchovy(), | |
Top( | |
Tuna(), | |
Top(Anchovy(), Bot())))) | |
.remA == | |
Top( | |
Salmon(), | |
Top(Tuna(), Bot())) | |
// === step8 === | |
trait Pie { | |
val remFn = new RemA | |
val rfFn = new RemFish | |
def remA: Pie | |
def remFish(f: Fish): Pie | |
} | |
case class Bot() extends Pie { | |
def remA = remFn.forBot | |
def remFish(f: Fish) = rfFn.forBot(f) | |
} | |
case class Top(t: Object, r: Pie) extends Pie { | |
def remA = remFn.forTop(t, r) | |
def remFish(f: Fish) = rfFn.forTop(t, r, f) | |
} | |
trait Fish | |
case class Anchovy() extends Fish | |
case class Salmon() extends Fish | |
case class Tuna() extends Fish | |
class RemA { | |
def forBot: Pie = Bot() | |
def forTop(t: Object, r: Pie): Pie = if (Anchovy() == t) r.remA else Top(t, r.remA) | |
} | |
class RemFish { | |
def forBot(f: Fish): Pie = Bot() | |
def forTop(t: Object, r: Pie, f: Fish): Pie = if (f == t) r.remFish(f) else Top(t, r.remFish(f)) | |
} | |
Top( | |
Salmon(), | |
Top( | |
Anchovy(), | |
Top( | |
Tuna(), | |
Top(Anchovy(), Bot())))) | |
.remFish(Anchovy()) == | |
Top( | |
Salmon(), | |
Top(Tuna(), Bot())) | |
Top( | |
Salmon(), | |
Top( | |
Anchovy(), | |
Top( | |
Tuna(), | |
Top(Anchovy(), Bot())))) | |
.remFish(Salmon()) == | |
Top( | |
Anchovy(), | |
Top( | |
Tuna(), | |
Top(Anchovy(), Bot()))) | |
// === step9 === | |
type Stuff = Any | |
trait Pie { | |
val rfFn = new RemFish | |
val riFn = new RemInt | |
def remFish(f: Fish): Pie | |
def remInt(i: Int): Pie | |
} | |
case class Bot() extends Pie { | |
def remFish(f: Fish) = rfFn.forBot(f) | |
def remInt(i: Int) = riFn.forBot(i) | |
} | |
case class Top(t: Stuff, r: Pie) extends Pie { | |
def remFish(f: Fish) = rfFn.forTop(t, r, f) | |
def remInt(i: Int) = riFn.forTop(t, r, i) | |
} | |
trait Fish | |
case class Anchovy() extends Fish | |
case class Salmon() extends Fish | |
case class Tuna() extends Fish | |
class RemFish { | |
def forBot(f: Fish): Pie = Bot() | |
def forTop(t: Stuff, r: Pie, f: Fish): Pie = if (f == t) r.remFish(f) else Top(t, r.remFish(f)) | |
} | |
class RemInt { | |
def forBot(i: Int): Pie = Bot() | |
def forTop(t: Stuff, r: Pie, i: Int): Pie = if (i == t) r.remInt(i) else Top(t, r.remInt(i)) | |
} | |
Top(2, | |
Top(3, | |
Top(2, Bot()))) | |
.remInt(3) == Top(2, Top(2, Bot())) | |
// === step10 === | |
trait Pie { | |
val remFn = new Rem | |
def rem(o: Stuff): Pie | |
} | |
case class Bot() extends Pie { | |
def rem(o: Stuff) = remFn.forBot(o) | |
} | |
case class Top(t: Stuff, r: Pie) extends Pie { | |
def rem(o: Stuff) = remFn.forTop(t, r, o) | |
} | |
trait Fish | |
case class Anchovy() extends Fish | |
case class Salmon() extends Fish | |
case class Tuna() extends Fish | |
class Rem { | |
def forBot(f: Stuff): Pie = Bot() | |
def forTop(t: Stuff, r: Pie, o: Stuff): Pie = if (o == t) r.rem(o) else Top(t, r.rem(o)) | |
} | |
// === step11 === | |
trait Pie { | |
val remFn = new Rem | |
val substFn = new Subst | |
def rem(o: Stuff): Pie | |
def subst(n: Stuff, o: Stuff): Pie | |
} | |
case class Bot() extends Pie { | |
def rem(o: Stuff) = remFn.forBot(o) | |
def subst(n: Stuff, o: Stuff) = substFn.forBot(n, o) | |
} | |
case class Top(t: Stuff, r: Pie) extends Pie { | |
def rem(o: Stuff) = remFn.forTop(t, r, o) | |
def subst(n: Stuff, o: Stuff) = substFn.forTop(t, r, n, o) | |
} | |
trait Fish | |
case class Anchovy() extends Fish | |
case class Salmon() extends Fish | |
case class Tuna() extends Fish | |
class Rem { | |
def forBot(f: Stuff): Pie = Bot() | |
def forTop(t: Stuff, r: Pie, o: Stuff): Pie = if (o == t) r.rem(o) else Top(t, r.rem(o)) | |
} | |
class Subst { | |
def forBot(n: Stuff, o: Stuff): Pie = Bot() | |
def forTop(t: Stuff, r: Pie, n: Stuff, o: Stuff): Pie = if (o == t) Top(n, r.subst(n, o)) else Top(t, r.subst(n, o)) | |
} | |
Top(Anchovy(), | |
Top(Tuna(), | |
Top(Anchovy(), Bot()))) | |
.subst(Salmon(), Anchovy()) == | |
Top(Salmon(), | |
Top(Tuna(), | |
Top(Salmon(), Bot()))) | |
// === step12 === | |
trait Pie { | |
def rem(rem: Rem): Pie | |
def subst(subst: Subst): Pie | |
} | |
case class Bot() extends Pie { | |
def rem(rem: Rem) = rem.forBot | |
def subst(subst: Subst) = subst.forBot | |
} | |
case class Top(t: Stuff, r: Pie) extends Pie { | |
def rem(rem: Rem) = rem.forTop(t, r) | |
def subst(subst: Subst) = subst.forTop(t, r) | |
} | |
trait Fish | |
case class Anchovy() extends Fish | |
case class Salmon() extends Fish | |
case class Tuna() extends Fish | |
class Rem(o: Stuff) { | |
def forBot: Pie = Bot() | |
def forTop(t: Stuff, r: Pie): Pie = if (o == t) r.rem(this) else Top(t, r.rem(this)) | |
} | |
class Subst(n: Stuff, o: Stuff) { | |
def forBot: Pie = Bot() | |
def forTop(t: Stuff, r: Pie): Pie = if (o == t) Top(n, r.subst(this)) else Top(t, r.subst(this)) | |
} | |
// === step13 === | |
trait Pie { | |
def accept(ask: PieVisitor): Pie | |
} | |
case class Bot() extends Pie { | |
def accept(ask: PieVisitor) = ask.forBot | |
} | |
case class Top(t: Stuff, r: Pie) extends Pie { | |
def accept(ask: PieVisitor) = ask.forTop(t, r) | |
} | |
trait Fish | |
case class Anchovy() extends Fish | |
case class Salmon() extends Fish | |
case class Tuna() extends Fish | |
trait PieVisitor { | |
def forBot: Pie | |
def forTop(t: Stuff, r: Pie): Pie | |
} | |
case class Rem(o: Stuff) extends PieVisitor { | |
def forBot: Pie = Bot() | |
def forTop(t: Stuff, r: Pie): Pie = if (o == t) r.accept(this) else Top(t, r.accept(this)) | |
} | |
case class Subst(n: Stuff, o: Stuff) extends PieVisitor { | |
def forBot: Pie = Bot() | |
def forTop(t: Stuff, r: Pie): Pie = if (o == t) Top(n, r.accept(this)) else Top(t, r.accept(this)) | |
} | |
// === step14 === | |
trait Pie { | |
def accept(ask: PieVisitor): Pie | |
} | |
case class Bot() extends Pie { | |
def accept(ask: PieVisitor) = ask.forBot | |
} | |
case class Top(t: Stuff, r: Pie) extends Pie { | |
def accept(ask: PieVisitor) = ask.forTop(t, r) | |
} | |
trait Fish | |
case class Anchovy() extends Fish | |
case class Salmon() extends Fish | |
case class Tuna() extends Fish | |
trait PieVisitor { | |
def forBot: Pie | |
def forTop(t: Stuff, r: Pie): Pie | |
} | |
case class Rem(o: Stuff) extends PieVisitor { | |
def forBot: Pie = Bot() | |
def forTop(t: Stuff, r: Pie): Pie = if (o == t) r.accept(this) else Top(t, r.accept(this)) | |
} | |
case class Subst(n: Stuff, o: Stuff) extends PieVisitor { | |
def forBot: Pie = Bot() | |
def forTop(t: Stuff, r: Pie): Pie = if (o == t) Top(n, r.accept(this)) else Top(t, r.accept(this)) | |
} | |
case class LtdSubst(c: Int, n: Stuff, o: Stuff) extends PieVisitor { | |
def forBot: Pie = Bot() | |
def forTop(t: Stuff, r: Pie): Pie = if (c == 0) Top(t, r) else if (o == t) Top(n, r.accept(LtdSubst(c-1, n, o))) else Top(t, r.accept(this)) | |
} | |
// === step15 === | |
trait Fruit | |
case class Peach() extends Fruit | |
case class Apple() extends Fruit | |
case class Pear() extends Fruit | |
case class Lemon() extends Fruit | |
case class Fig() extends Fruit | |
trait Tree { | |
def accept(ask: bTreeVisitor): Boolean | |
} | |
case class Bud() extends Tree { | |
def accept(ask: bTreeVisitor) = ask.forBud | |
} | |
case class Flat(f: Fruit, t: Tree) extends Tree { | |
def accept(ask: bTreeVisitor) = ask.forFlat(f, t) | |
} | |
case class Split(l: Tree, r: Tree) extends Tree { | |
def accept(ask: bTreeVisitor) = ask.forSplit(l, r) | |
} | |
trait bTreeVisitor { | |
def forBud: Boolean | |
def forFlat(f: Fruit, t: Tree): Boolean | |
def forSplit(l: Tree, r: Tree): Boolean | |
} | |
case class bIsFlat() extends bTreeVisitor { | |
def forBud = true | |
def forFlat(f: Fruit, t: Tree) = t.accept(this) | |
def forSplit(l: Tree, r: Tree) = false | |
} | |
case class bIsSplit() extends bTreeVisitor { | |
def forBud = true | |
def forFlat(f: Fruit, t: Tree) = false | |
def forSplit(l: Tree, r: Tree) = if (l.accept(this)) r.accept(this) else false | |
} | |
case class bHasFruit() extends bTreeVisitor { | |
def forBud = false | |
def forFlat(f: Fruit, t: Tree) = true | |
def forSplit(l: Tree, r: Tree) = if (l.accept(this)) true else r.accept(this) | |
} | |
Flat(Apple(), Flat(Peach(), Bud())) | |
.accept(bIsFlat()) should be (true) | |
Split(Bud(), Flat(Fig(), Split(Bud(), Bud()))) | |
.accept(bIsSplit()) should be (false) | |
Split( | |
Split(Bud(), Split(Bud(), Bud())), | |
Split(Bud(), Split(Bud(), Bud()))) | |
.accept(bHasFruit()) should be (false) | |
// === step16 === | |
trait Fruit | |
case class Peach() extends Fruit | |
case class Apple() extends Fruit | |
case class Pear() extends Fruit | |
case class Lemon() extends Fruit | |
case class Fig() extends Fruit | |
trait Tree { | |
def accept(ask: bTreeVisitor): Boolean | |
def accept(ask: iTreeVisitor): Int | |
def accept(ask: tTreeVisitor): Tree | |
} | |
case class Bud() extends Tree { | |
def accept(ask: bTreeVisitor) = ask.forBud | |
def accept(ask: iTreeVisitor) = ask.forBud | |
def accept(ask: tTreeVisitor) = ask.forBud | |
} | |
case class Flat(f: Fruit, t: Tree) extends Tree { | |
def accept(ask: bTreeVisitor) = ask.forFlat(f, t) | |
def accept(ask: iTreeVisitor) = ask.forFlat(f, t) | |
def accept(ask: tTreeVisitor) = ask.forFlat(f, t) | |
} | |
case class Split(l: Tree, r: Tree) extends Tree { | |
def accept(ask: bTreeVisitor) = ask.forSplit(l, r) | |
def accept(ask: iTreeVisitor) = ask.forSplit(l, r) | |
def accept(ask: tTreeVisitor) = ask.forSplit(l, r) | |
} | |
trait bTreeVisitor { | |
def forBud: Boolean | |
def forFlat(f: Fruit, t: Tree): Boolean | |
def forSplit(l: Tree, r: Tree): Boolean | |
} | |
case class bIsFlat() extends bTreeVisitor { | |
def forBud = true | |
def forFlat(f: Fruit, t: Tree) = t.accept(this) | |
def forSplit(l: Tree, r: Tree) = false | |
} | |
case class bIsSplit() extends bTreeVisitor { | |
def forBud = true | |
def forFlat(f: Fruit, t: Tree) = false | |
def forSplit(l: Tree, r: Tree) = if (l.accept(this)) r.accept(this) else false | |
} | |
case class bHasFruit() extends bTreeVisitor { | |
def forBud = false | |
def forFlat(f: Fruit, t: Tree) = true | |
def forSplit(l: Tree, r: Tree) = if (l.accept(this)) true else r.accept(this) | |
} | |
trait iTreeVisitor { | |
def forBud: Int | |
def forFlat(f: Fruit, t: Tree): Int | |
def forSplit(l: Tree, r: Tree): Int | |
} | |
case class iHeight() extends iTreeVisitor { | |
def forBud = 0 | |
def forFlat(f: Fruit, t: Tree) = t.accept(this) + 1 | |
def forSplit(l: Tree, r: Tree) = l.accept(this) max r.accept(this) + 1 | |
} | |
trait tTreeVisitor { | |
def forBud: Tree | |
def forFlat(f: Fruit, t: Tree): Tree | |
def forSplit(l: Tree, r: Tree): Tree | |
} | |
case class tSubst(n: Fruit, o: Fruit) extends tTreeVisitor { | |
def forBud = Bud() | |
def forFlat(f: Fruit, t: Tree) = if (o == f) Flat(n, t.accept(this)) else Flat(f, t.accept(this)) | |
def forSplit(l: Tree, r: Tree) = Split(l.accept(this), r.accept(this)) | |
} | |
Split( | |
Split(Bud(), Flat(Lemon(), Bud())), | |
Flat(Fig(), Split(Bud(), Bud()))) | |
.accept(iHeight()) should be (3) | |
// === step17 === | |
type AnyThing = Any | |
trait Fruit | |
case class Peach() extends Fruit | |
case class Apple() extends Fruit | |
case class Pear() extends Fruit | |
case class Lemon() extends Fruit | |
case class Fig() extends Fruit | |
trait Tree { | |
def accept(ask: TreeVisitor): AnyThing | |
} | |
case class Bud() extends Tree { | |
def accept(ask: TreeVisitor) = ask.forBud | |
} | |
case class Flat(f: Fruit, t: Tree) extends Tree { | |
def accept(ask: TreeVisitor) = ask.forFlat(f, t) | |
} | |
case class Split(l: Tree, r: Tree) extends Tree { | |
def accept(ask: TreeVisitor) = ask.forSplit(l, r) | |
} | |
trait TreeVisitor { | |
def forBud: AnyThing | |
def forFlat(f: Fruit, t: Tree): AnyThing | |
def forSplit(l: Tree, r: Tree): AnyThing | |
} | |
case class bIsFlat() extends TreeVisitor { | |
def forBud = true | |
def forFlat(f: Fruit, t: Tree) = t.accept(this) | |
def forSplit(l: Tree, r: Tree) = false | |
} | |
case class bIsSplit() extends TreeVisitor { | |
def forBud = true | |
def forFlat(f: Fruit, t: Tree) = false | |
def forSplit(l: Tree, r: Tree) = if (l.accept(this).asInstanceOf[Boolean]) r.accept(this) else false | |
} | |
case class bHasFruit() extends TreeVisitor { | |
def forBud = false | |
def forFlat(f: Fruit, t: Tree) = true | |
def forSplit(l: Tree, r: Tree) = if (l.accept(this).asInstanceOf[Boolean]) true else r.accept(this) | |
} | |
case class iHeight() extends TreeVisitor { | |
def forBud = 0 | |
def forFlat(f: Fruit, t: Tree) = t.accept(this).asInstanceOf[Int] + 1 | |
def forSplit(l: Tree, r: Tree) = l.accept(this).asInstanceOf[Int] max r.accept(this).asInstanceOf[Int] + 1 | |
} | |
case class tSubst(n: Fruit, o: Fruit) extends TreeVisitor { | |
def forBud = Bud() | |
def forFlat(f: Fruit, t: Tree) = if (o == f) Flat(n, t.accept(this).asInstanceOf[Tree]) else Flat(f, t.accept(this).asInstanceOf[Tree]) | |
def forSplit(l: Tree, r: Tree) = Split(l.accept(this).asInstanceOf[Tree], r.accept(this).asInstanceOf[Tree]) | |
} | |
// === step18 === | |
trait Fruit | |
case class Peach() extends Fruit | |
case class Apple() extends Fruit | |
case class Pear() extends Fruit | |
case class Lemon() extends Fruit | |
case class Fig() extends Fruit | |
trait Tree { | |
def accept(ask: TreeVisitor): AnyThing | |
} | |
case class Bud() extends Tree { | |
def accept(ask: TreeVisitor) = ask.forBud | |
} | |
case class Flat(f: Fruit, t: Tree) extends Tree { | |
def accept(ask: TreeVisitor) = ask.forFlat(f, t) | |
} | |
case class Split(l: Tree, r: Tree) extends Tree { | |
def accept(ask: TreeVisitor) = ask.forSplit(l, r) | |
} | |
trait TreeVisitor { | |
def forBud: AnyThing | |
def forFlat(f: Fruit, t: Tree): AnyThing | |
def forSplit(l: Tree, r: Tree): AnyThing | |
} | |
case class IsFlat() extends TreeVisitor { | |
def forBud = true | |
def forFlat(f: Fruit, t: Tree) = t.accept(this) | |
def forSplit(l: Tree, r: Tree) = false | |
} | |
case class IsSplit() extends TreeVisitor { | |
def forBud = true | |
def forFlat(f: Fruit, t: Tree) = false | |
def forSplit(l: Tree, r: Tree) = if (l.accept(this).asInstanceOf[Boolean]) r.accept(this) else false | |
} | |
case class HasFruit() extends TreeVisitor { | |
def forBud = false | |
def forFlat(f: Fruit, t: Tree) = true | |
def forSplit(l: Tree, r: Tree) = if (l.accept(this).asInstanceOf[Boolean]) true else r.accept(this) | |
} | |
case class Height() extends TreeVisitor { | |
def forBud = 0 | |
def forFlat(f: Fruit, t: Tree) = t.accept(this).asInstanceOf[Int] + 1 | |
def forSplit(l: Tree, r: Tree) = l.accept(this).asInstanceOf[Int] max r.accept(this).asInstanceOf[Int] + 1 | |
} | |
case class Subst(n: Fruit, o: Fruit) extends TreeVisitor { | |
def forBud = Bud() | |
def forFlat(f: Fruit, t: Tree) = if (o == f) Flat(n, t.accept(this).asInstanceOf[Tree]) else Flat(f, t.accept(this).asInstanceOf[Tree]) | |
def forSplit(l: Tree, r: Tree) = Split(l.accept(this).asInstanceOf[Tree], r.accept(this).asInstanceOf[Tree]) | |
} | |
case class Occurs(a: Fruit) extends TreeVisitor { | |
def forBud = 0 | |
def forFlat(f: Fruit, t: Tree) = if (a == f) t.accept(this).asInstanceOf[Int] + 1 else t.accept(this) | |
def forSplit(l: Tree, r: Tree) = l.accept(this).asInstanceOf[Int] + r.accept(this).asInstanceOf[Int] | |
} | |
// === step19 === | |
type AnyThing = Any | |
trait Expr { | |
def accept(ask: ExprVisitor): AnyThing | |
} | |
case class Plus(l: Expr, r: Expr) extends Expr { | |
def accept(ask: ExprVisitor) = ask.forPlus(l, r) | |
} | |
case class Diff(l: Expr, r: Expr) extends Expr { | |
def accept(ask: ExprVisitor) = ask.forDiff(l, r) | |
} | |
case class Prod(l: Expr, r: Expr) extends Expr { | |
def accept(ask: ExprVisitor) = ask.forProd(l, r) | |
} | |
case class Const(i: Int) extends Expr { | |
def accept(ask: ExprVisitor) = ask.forConst(i) | |
} | |
trait Set { | |
def add(i: Int) = if (mem(i)) this else Add(i, this) | |
def mem(i: Int): Boolean | |
def plus(s: Set): Set | |
def diff(s: Set): Set | |
def prod(s: Set): Set | |
} | |
case class Empty() extends Set { | |
def mem(i: Int) = false | |
def plus(s: Set) = s | |
def diff(s: Set) = Empty() | |
def prod(s: Set) = Empty() | |
} | |
case class Add(i: Int, s: Set) extends Set { | |
def mem(n: Int) = if (i == n) true else s.mem(n) | |
def plus(t: Set) = s.plus(t.add(i)) | |
def diff(t: Set) = if (t.mem(i)) s.diff(t) else s.diff(t).add(i) | |
def prod(t: Set) = if (t.mem(i)) s.prod(t).add(i) else s.prod(t) | |
} | |
trait ExprVisitor { | |
def forPlus(l: Expr, r: Expr): AnyThing | |
def forDiff(l: Expr, r: Expr): AnyThing | |
def forProd(l: Expr, r: Expr): AnyThing | |
def forConst(c: AnyThing): AnyThing | |
} | |
case class IntEval() extends ExprVisitor { | |
def forPlus(l: Expr, r: Expr) = plus(l.accept(this), r.accept(this)) | |
def forDiff(l: Expr, r: Expr) = diff(l.accept(this), r.accept(this)) | |
def forProd(l: Expr, r: Expr) = prod(l.accept(this), r.accept(this)) | |
def forConst(c: AnyThing) = c | |
private def plus(l: AnyThing, r: AnyThing): AnyThing = l.asInstanceOf[Int] + r.asInstanceOf[Int] | |
private def diff(l: AnyThing, r: AnyThing): AnyThing = l.asInstanceOf[Int] - r.asInstanceOf[Int] | |
private def prod(l: AnyThing, r: AnyThing): AnyThing = l.asInstanceOf[Int] * r.asInstanceOf[Int] | |
} | |
Plus(Const(1), Const(5)) | |
.accept(IntEval()).asInstanceOf[Int] should be (6) | |
Diff(Const(1), Const(5)) | |
.accept(IntEval()).asInstanceOf[Int] should be (-4) | |
Prod(Const(1), Const(5)) | |
.accept(IntEval()).asInstanceOf[Int] should be (5) | |
// === step20 === | |
trait Expr { | |
def accept(ask: ExprVisitor): AnyThing | |
} | |
case class Plus(l: Expr, r: Expr) extends Expr { | |
def accept(ask: ExprVisitor) = ask.forPlus(l, r) | |
} | |
case class Diff(l: Expr, r: Expr) extends Expr { | |
def accept(ask: ExprVisitor) = ask.forDiff(l, r) | |
} | |
case class Prod(l: Expr, r: Expr) extends Expr { | |
def accept(ask: ExprVisitor) = ask.forProd(l, r) | |
} | |
case class Const(s: Set) extends Expr { | |
def accept(ask: ExprVisitor) = ask.forConst(s) | |
} | |
trait Set { | |
def add(i: Int) = if (mem(i)) this else Add(i, this) | |
def mem(i: Int): Boolean | |
def plus(s: Set): Set | |
def diff(s: Set): Set | |
def prod(s: Set): Set | |
} | |
case class Empty() extends Set { | |
def mem(i: Int) = false | |
def plus(s: Set) = s | |
def diff(s: Set) = Empty() | |
def prod(s: Set) = Empty() | |
} | |
case class Add(i: Int, s: Set) extends Set { | |
def mem(n: Int) = if (i == n) true else s.mem(n) | |
def plus(t: Set) = s.plus(t.add(i)) | |
def diff(t: Set) = if (t.mem(i)) s.diff(t) else s.diff(t).add(i) | |
def prod(t: Set) = if (t.mem(i)) s.prod(t).add(i) else s.prod(t) | |
} | |
trait ExprVisitor { | |
def forPlus(l: Expr, r: Expr): AnyThing | |
def forDiff(l: Expr, r: Expr): AnyThing | |
def forProd(l: Expr, r: Expr): AnyThing | |
def forConst(c: AnyThing): AnyThing | |
} | |
trait Eval extends ExprVisitor { | |
def forPlus(l: Expr, r: Expr) = plus(l.accept(this), r.accept(this)) | |
def forDiff(l: Expr, r: Expr) = diff(l.accept(this), r.accept(this)) | |
def forProd(l: Expr, r: Expr) = prod(l.accept(this), r.accept(this)) | |
def forConst(c: AnyThing) = c | |
protected def plus(l: AnyThing, r: AnyThing): AnyThing | |
protected def diff(l: AnyThing, r: AnyThing): AnyThing | |
protected def prod(l: AnyThing, r: AnyThing): AnyThing | |
} | |
case class IntEval() extends Eval { | |
protected def plus(l: AnyThing, r: AnyThing) = l.asInstanceOf[Int] + r.asInstanceOf[Int] | |
protected def diff(l: AnyThing, r: AnyThing) = l.asInstanceOf[Int] - r.asInstanceOf[Int] | |
protected def prod(l: AnyThing, r: AnyThing) = l.asInstanceOf[Int] * r.asInstanceOf[Int] | |
} | |
case class SetEval() extends Eval { | |
protected def plus(l: AnyThing, r: AnyThing) = l.asInstanceOf[Set] plus r.asInstanceOf[Set] | |
protected def diff(l: AnyThing, r: AnyThing) = l.asInstanceOf[Set] diff r.asInstanceOf[Set] | |
protected def prod(l: AnyThing, r: AnyThing) = l.asInstanceOf[Set] prod r.asInstanceOf[Set] | |
} | |
// === step21 === | |
trait Pie { | |
def accept(ask: PieVisitor): Pie | |
} | |
case class Bot() extends Pie { | |
def accept(ask: PieVisitor) = ask.forBot | |
} | |
case class Top(t: Stuff, r: Pie) extends Pie { | |
def accept(ask: PieVisitor) = ask.forTop(t, r) | |
} | |
trait Fish | |
case class Anchovy() extends Fish | |
case class Salmon() extends Fish | |
case class Tuna() extends Fish | |
trait PieVisitor { | |
def forBot: Pie | |
def forTop(t: Stuff, r: Pie): Pie | |
} | |
case class Rem(o: Stuff) extends PieVisitor { | |
def forBot: Pie = Bot() | |
def forTop(t: Stuff, r: Pie): Pie = if (o == t) r.accept(this) else Top(t, r.accept(this)) | |
} | |
abstract class Subst(n: Stuff, o: Stuff) extends PieVisitor { | |
def forBot: Pie = Bot() | |
def forTop(t: Stuff, r: Pie): Pie | |
} | |
case class SimpleSubst(n: Stuff, o: Stuff) extends Subst(n, o) { | |
def forTop(t: Stuff, r: Pie) = if (o == t) Top(n, r.accept(this)) else Top(t, r.accept(this)) | |
} | |
case class LtdSubst(c: Int, n: Stuff, o: Stuff) extends Subst(n, o) { | |
def forTop(t: Stuff, r: Pie): Pie = if (c == 0) Top(t, r) else if (o == t) Top(n, r.accept(LtdSubst(c-1, n, o))) else Top(t, r.accept(this)) | |
} | |
// test | |
import org.scalatest.{FlatSpec, Matchers} | |
class PieTest extends FlatSpec with Matchers { | |
info("PieTest") | |
"all remFish test" should "be passed" in { | |
Top( | |
Salmon(), | |
Top( | |
Anchovy(), | |
Top( | |
Tuna(), | |
Top(Anchovy(), Bot())))) | |
.accept(new Rem(Anchovy())) should be ( | |
Top( | |
Salmon(), | |
Top(Tuna(), Bot()))) | |
Top( | |
Salmon(), | |
Top( | |
Anchovy(), | |
Top( | |
Tuna(), | |
Top(Anchovy(), Bot())))) | |
.accept(Rem(Salmon())) should be ( | |
Top( | |
Anchovy(), | |
Top( | |
Tuna(), | |
Top(Anchovy(), Bot())))) | |
} | |
"all remInt test" should "be passed" in { | |
Top(2, | |
Top(3, | |
Top(2, Bot()))) | |
.accept(Rem(3)) should be (Top(2, Top(2, Bot()))) | |
} | |
"all subst test" should "be passed" in { | |
Top(Anchovy(), | |
Top(Tuna(), | |
Top(Anchovy(), Bot()))) | |
.accept(SimpleSubst(Salmon(), Anchovy())) should be ( | |
Top(Salmon(), | |
Top(Tuna(), | |
Top(Salmon(), Bot())))) | |
} | |
"all LtdSubst test" should "be passed" in { | |
Top(Anchovy(), | |
Top(Tuna(), | |
Top(Anchovy(), | |
Top(Tuna(), | |
Top(Anchovy(), | |
Bot()))))) | |
.accept(LtdSubst(2, Salmon(), Anchovy())) should be ( | |
Top(Salmon(), | |
Top(Tuna(), | |
Top(Salmon(), | |
Top(Tuna(), | |
Top(Anchovy(), | |
Bot()))))) | |
) | |
} | |
info("Ok") | |
} | |
// === step22 === | |
abstract class Point(val x: Int, val y: Int) { | |
def closerToO(p: Point): Boolean = distanceToO < p.distanceToO | |
def distanceToO: Int | |
def minus(p: Point): Point = new CartesianPt(x - p.x, y - p.y) | |
} | |
import math._ | |
class CartesianPt(x: Int, y: Int) extends Point(x, y) { | |
def distanceToO = sqrt(pow(x, 2) + pow(y, 2)).toInt | |
} | |
class ManhattanPt(x: Int, y: Int) extends Point(x, y) { | |
def distanceToO = x + y | |
} | |
class ShadowedCartesianPt(x: Int, y: Int, _x: Int, _y: Int) extends CartesianPt(x, y) { | |
override def distanceToO = new CartesianPt(x + _x, y + _y).distanceToO | |
} | |
class ShadowManhattanPt(x: Int, y: Int, _x: Int, _y: Int) extends ManhattanPt(x, y) { | |
override def distanceToO = super.distanceToO + _x + _y | |
} | |
trait Shape { | |
def accept(ask: ShapeVisitor): Boolean | |
} | |
case class Circle(r: Int) extends Shape { | |
def accept(ask: ShapeVisitor) = ask.forCircle(r) | |
} | |
case class Square(s: Int) extends Shape { | |
def accept(ask: ShapeVisitor) = ask.forSquare(s) | |
} | |
case class Trans(q: Point, s: Shape) extends Shape { | |
def accept(ask: ShapeVisitor) = ask.forTrans(q, s) | |
} | |
trait ShapeVisitor { | |
def forCircle(r: Int): Boolean | |
def forSquare(s: Int): Boolean | |
def forTrans(q: Point, s: Shape): Boolean | |
} | |
class HasPt(p: Point) extends ShapeVisitor { | |
def forCircle(r: Int) = p.distanceToO <= r | |
def forSquare(s: Int) = if (p.x <= s) p.y <= s else false | |
protected def newHasPt(p: Point): ShapeVisitor = new HasPt(p) | |
def forTrans(q: Point, s: Shape) = s.accept(newHasPt(p.minus(q))) | |
} | |
trait UnionVisitor extends ShapeVisitor { | |
def forUnion(s: Shape, t: Shape): Boolean | |
} | |
case class Union(s: Shape, t: Shape) extends Shape { | |
def accept(ask: ShapeVisitor) = ask.asInstanceOf[UnionVisitor].forUnion(s, t) | |
} | |
class UnionHasPt(p: Point) extends HasPt(p) with UnionVisitor { | |
override protected def newHasPt(p: Point): ShapeVisitor = new UnionHasPt(p) | |
def forUnion(s: Shape, t: Shape) = if (s.accept(this)) true else t.accept(this) | |
} | |
// test | |
import org.scalatest.{FlatSpec, Matchers} | |
class PointTest extends FlatSpec with Matchers { | |
info("PointTest") | |
"all tests" should "be passed" in { | |
new ShadowManhattanPt(2, 3, 1, 0).distanceToO should be (6) | |
new CartesianPt(3, 4).closerToO(new ShadowedCartesianPt(1, 5, 1, 2)) should be (true) | |
} | |
"another tests" should "be passed" in { | |
Circle(10).accept(new HasPt(new CartesianPt(10, 10))) should be (false) | |
Square(10).accept(new HasPt(new CartesianPt(10, 10))) should be (true) | |
Trans(new CartesianPt(5, 6), Circle(10)).accept(new HasPt(new CartesianPt(10, 10))) should be (true) | |
Trans(new CartesianPt(5, 4), Trans(new CartesianPt(5, 6), Circle(10))).accept(new HasPt(new CartesianPt(10, 10))) should be (true) | |
} | |
"the third tests" should "be passed" in { | |
Trans(new CartesianPt(12, 2), Union(Square(10), Trans(new CartesianPt(4, 4), Circle(5)))).accept(new UnionHasPt(new CartesianPt(12, 16))) should be (false) | |
Trans(new CartesianPt(3, 7), Union(Square(10), Circle(10))).accept(new UnionHasPt(new CartesianPt(13, 17))) should be (true) | |
} | |
info("Ok") | |
} | |
// === step23 === | |
type Stuff = Any | |
trait Pieman { | |
def addTop(t: Stuff): Int | |
def remTop(t: Stuff): Int | |
def substTop(n: Stuff, o: Stuff): Int | |
def occTop(o: Stuff): Int | |
} | |
case class MrPieman() extends Pieman { | |
private var p: Pie = Bot() | |
def addTop(t: Stuff) = { | |
p = Top(t, p) | |
occTop(t) | |
} | |
def remTop(t: Stuff) = { | |
p = p.accept(Rem(t)).asInstanceOf[Pie] | |
occTop(t) | |
} | |
def substTop(n: Stuff, o: Stuff) = { | |
p = p.accept(Subst(n, o)).asInstanceOf[Pie] | |
occTop(n) | |
} | |
def occTop(o: Stuff) = p.accept(Occurs(o)).asInstanceOf[Int] | |
} | |
trait PieVisitor { | |
def forBot: Stuff | |
def forTop(t: Stuff, r: Pie): Stuff | |
} | |
case class Occurs(a: Stuff) extends PieVisitor { | |
def forBot = 0 | |
def forTop(t: Stuff, r: Pie) = { | |
if (t == a) r.accept(this).asInstanceOf[Int] + 1 else r.accept(this).asInstanceOf[Int] | |
} | |
} | |
case class Subst(n: Stuff, o: Stuff) extends PieVisitor { | |
def forBot = Bot() | |
def forTop(t: Stuff, r: Pie) = if (o == t) Top(n, r.accept(this).asInstanceOf[Pie]) | |
} | |
case class Rem(o: Stuff) extends PieVisitor { | |
def forBot = Bot() | |
def forTop(t: Stuff, r: Pie) = if (o == t) r.accept(this) else Top(t, r.accept(this).asInstanceOf[Pie]) | |
} | |
trait Pie { | |
def accept(ask: PieVisitor): Stuff | |
} | |
case class Bot() extends Pie { | |
def accept(ask: PieVisitor) = ask.forBot | |
} | |
case class Top(t: Stuff, r: Pie) extends Pie { | |
def accept(ask: PieVisitor) = ask.forTop(t, r) | |
} | |
trait Fish | |
case class Anchovy() extends Fish | |
case class Salmon() extends Fish | |
case class Tuna() extends Fish | |
// test | |
import org.scalatest.{Matchers, FlatSpec} | |
class PiemanTest extends FlatSpec with Matchers { | |
info("PiemanTest") | |
"all tests" should "be passed" in { | |
MrPieman() addTop Anchovy() should be (1) | |
} | |
"another tests" should "be passed" in { | |
val yy = MrPieman() | |
yy addTop Anchovy() | |
yy addTop Anchovy() | |
yy addTop Salmon() | |
yy addTop Tuna() | |
yy addTop Tuna() | |
yy substTop (Tuna(), Anchovy()) | |
yy remTop Tuna() should be (0) | |
} | |
info("Ok") | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment