Instantly share code, notes, and snippets.

# grzegorzbalcerek/ExpressionProblem1_1.scala

Last active April 7, 2016 21:48
Show Gist options
• Save grzegorzbalcerek/79947dbd1ae4b16e80da to your computer and use it in GitHub Desktop.
The Expression Problem
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
 trait Module { type shape }
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
 trait Module2 extends Module { trait Shape { def area: Double } type shape <: Shape class Circle(val r: Double) extends Shape { def area = Math.PI*r*r } } object Module2Test extends App with Module2 { println("Module2Test") type shape = Shape val s1: shape = new Circle(1) val s2: shape = new Circle(3) println(s1.area) println(s2.area) }
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
 trait Module3 extends Module2 { trait Shape extends super.Shape { def scale(n: Double): shape } type shape <: Shape class Circle(r: Double) extends super.Circle(r) with Shape { def scale(n: Double) = Circle(n*r) } def Circle(r: Double): shape def scale(s: shape, n: Double) = s.scale(n) } trait Module3Final extends Module3 { type shape = Shape def Circle(r: Double): shape = new Circle(r) } object Module3Test extends App with Module3Final { println("Module3Test") val s1: shape = Circle(3) val s2: shape = s1.scale(4) val s3: shape = scale(s1,4) println(s1.area) println(s2.area) println(s3.area) }
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
 trait Module4 extends Module3 { trait Shape extends super.Shape { def circum: Double } type shape <: Shape class Circle(r: Double) extends super.Circle(r) with Shape { def circum = Math.PI*2*r } class Rect(val a: Double, val b: Double) extends Shape { def area = a*b def scale(n: Double): shape = Rect(n*a,n*b) def circum = 2*(a+b) } def Rect(a: Double, b: Double): shape } trait Module4Final extends Module4 { type shape = Shape def Circle(r: Double): shape = new Circle(r) def Rect(a: Double, b: Double): shape = new Rect(a,b) } object Module4Test extends App with Module4Final { println("Module4Test") val s1: shape = Circle(1) val s2: shape = Rect(2,4) val s3: shape = s1.scale(2) val s4: shape = s2.scale(2) val s5: shape = scale(s2,2) println((s1.area, s1.circum)) println((s2.area, s2.circum)) println((s3.area, s3.circum)) println((s4.area, s4.circum)) println((s5.area, s5.circum)) }
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
 trait Module { type shape }
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
 trait RectModule extends Module { trait Rect { def a: Double def b: Double } def Rect(a: Double, b: Double): shape } trait Module1 extends RectModule
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
 trait AreaModule { trait Area { def area: Double } } trait CircleModule extends Module { trait Circle { def r: Double } def Circle(r: Double): shape } trait CircleAreaModule extends AreaModule with CircleModule { trait CircleArea extends Circle with Area { def area = Math.PI*r*r } } trait RectAreaModule extends AreaModule with RectModule { trait RectArea extends Rect with Area { def area = a*b } } trait Module2 extends Module1 with CircleAreaModule with RectAreaModule { trait Shape extends Area trait Circle extends Shape with CircleArea trait Rect extends Shape with super.Rect with RectArea }
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
 trait CircumModule { trait Circum { def circum: Double } } trait RectCircumModule extends CircumModule with RectModule { trait RectCircum extends Circum with Rect { def circum = 2*(a+b) } } trait Module3 extends Module1 with RectCircumModule { trait Shape extends Circum trait Rect extends Shape with RectCircum }
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
 trait CircleCircumModule extends CircumModule with CircleModule { trait CircleCircum extends Circum with Circle { def circum = Math.PI*2*r } } trait Module4 extends Module2 with Module3 with CircleCircumModule { trait Shape extends super[Module2].Shape with super[Module3].Shape trait Rect extends Shape with super[Module2].Rect with super[Module3].Rect trait Circle extends Shape with super.Circle with CircleCircum } trait Module4Final extends Module4 { type shape = Shape class Circle(val r: Double) extends super.Circle def Circle(r: Double): shape = new Circle(r) class Rect(val a: Double, val b: Double) extends super.Rect def Rect(a: Double, b: Double): shape = new Rect(a,b) } object Test4 extends App with Module4Final { println("Test4") val s1: shape = Circle(1) val s2: shape = Rect(2,4) println(s1.area) println(s2.area) println(s1.circum) println(s2.circum) }
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
 trait Module5 extends Module with CircleCircumModule { trait Shape extends Circum trait Circle extends Shape with CircleCircum } trait Module5Final extends Module5 { type shape = Shape class Circle(val r: Double) extends super.Circle def Circle(r: Double): shape = new Circle(r) } object Test5 extends App with Module5Final { println("Test5") val s1: shape = Circle(1) println(s1.circum) }
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
 trait Area[S] { def area(s: S): Double } object Area { def area[S](s: S)(implicit as: Area[S]) = as.area(s) }
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
 case class Rect(a: Double, b: Double) object Rect { implicit object RectArea extends Area[Rect] { def area(r: Rect) = r.a * r.b } } object Test1 extends App { import Area._ val s1 = Rect(2,4) println( area(s1) ) }
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
 trait Scale[S] { def scale(s: S, n: Double): S } object Scale { def scale[S:Scale](s: S, n: Double) = implicitly[Scale[S]].scale(s,n) implicit object RectScale extends Scale[Rect] { def scale(r: Rect, n: Double) = Rect(r.a*n, r.b*n) } }
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
 case class Circle(r: Double) object Circle { implicit object CircleArea extends Area[Circle] { def area(c: Circle) = Math.PI*c.r*c.r } }
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
 object Test2 extends App { import Area._, Scale._ val s1 = Rect(2,4) val s2 = scale(s1,2) val s3 = Circle(1) println( area(s1) ) println( area(s2) ) println( area(s3) ) }
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
 object Test3 extends App { import Scale._ val s1 = Circle(1) println( scale(s1,2) ) // compilation error }
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
 trait Shape { def area: Double } class Rect(a: Double, b: Double) extends Shape { override def area = a*b } object Test extends App { val s1: Shape = new Rect(2,4) println( s1.area ) }
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
 sealed trait Shape case class Circle(r: Double) extends Shape case class Rect(a: Double, b: Double) extends Shape object Area { def area(s: Shape) = s match { case Circle(r) => Math.PI*r*r case Rect(a,b) => a*b } } object Test extends App { val s1: Shape = new Circle(1) val s2: Shape = new Rect(2,4) import Area._ println( area(s1) ) println( area(s2) ) }