Skip to content

Instantly share code, notes, and snippets.

@grzegorzbalcerek
Last active April 7, 2016 21:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save grzegorzbalcerek/79947dbd1ae4b16e80da to your computer and use it in GitHub Desktop.
Save grzegorzbalcerek/79947dbd1ae4b16e80da to your computer and use it in GitHub Desktop.
The Expression Problem
trait Module {
type shape
}
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)
}
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)
}
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))
}
trait Module {
type shape
}
trait RectModule extends Module {
trait Rect {
def a: Double
def b: Double
}
def Rect(a: Double, b: Double): shape
}
trait Module1 extends RectModule
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
}
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
}
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)
}
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)
}
trait Area[S] {
def area(s: S): Double
}
object Area {
def area[S](s: S)(implicit as: Area[S]) =
as.area(s)
}
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) )
}
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)
}
}
case class Circle(r: Double)
object Circle {
implicit object CircleArea
extends Area[Circle] {
def area(c: Circle) = Math.PI*c.r*c.r
}
}
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) )
}
object Test3 extends App {
import Scale._
val s1 = Circle(1)
println( scale(s1,2) ) // compilation error
}
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 )
}
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) )
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment