Skip to content

Instantly share code, notes, and snippets.

@kmizu
Created January 17, 2016 13:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kmizu/339dd78052c68914a412 to your computer and use it in GitHub Desktop.
Save kmizu/339dd78052c68914a412 to your computer and use it in GitHub Desktop.
Emulate Generics using Abstract Type Members
trait List {self =>
type E
def head: self.E
def tail: List { type E = self.E }
}
trait Cons extends List {self =>
val head: E
val tail: List { type E = self.E }
}
trait Nil extends List {self =>
def head: E = sys.error("no such element")
def tail: List { type E = self.E } = sys.error("empty list")
}
trait Function {
type In
type Out
def apply(arg: In): Out
}
trait Mapper {
type A
type B
def map(list: List { type E = A })(fun: Function { type In = A; type Out = B }): List { type E = B } = list match {
case x: Cons =>
new Cons {
type E = B
val head = fun.apply(x.head)
val tail = map(x.tail)(fun)
}
case x: Nil =>
new Nil {
type E = B
}
}
}
trait ForEach {
type A
def foreach(list: List { type E = A })(fun: Function { type In = A; type Out = Unit }): Unit = list match {
case x: Cons =>
fun.apply(x.head)
foreach(x.tail)(fun)
case x: Nil =>
()
}
}
object Main {
def main(args: Array[String]): Unit = {
val list = new Cons {
type E = Int
val head = 1
val tail = new Cons {
type E = Int
val head: E = 2
val tail = new Cons {
type E = Int
val head = 3
val tail = new Nil { type E = Int }
}
}
}
val newList = new Mapper {
type A = Int
type B = Int
}.map(list)(new Function {
type In = Int
type Out = Int
def apply(arg: In): Out = arg + 1
})
new ForEach {
type A = Int
}.foreach(newList)(new Function {
type In = Int
type Out = Unit
def apply(arg: In): Out = println(arg)
})
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment