Skip to content

Instantly share code, notes, and snippets.

@xstpl
Last active August 29, 2015 14:24
Show Gist options
  • Save xstpl/f5dd4a8f355f43992f83 to your computer and use it in GitHub Desktop.
Save xstpl/f5dd4a8f355f43992f83 to your computer and use it in GitHub Desktop.
// === 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