Skip to content

Instantly share code, notes, and snippets.

@rklaehn
Last active October 6, 2015 20:48
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 rklaehn/0f9271b2fc6ceeae699a to your computer and use it in GitHub Desktop.
Save rklaehn/0f9271b2fc6ceeae699a to your computer and use it in GitHub Desktop.
// -Yno-predef
package collection
import scala.Predef.{???, println, implicitly}
trait Foreachable[T, U] {
def foreach(value: T, f: U ⇒ Any): Unit
}
trait Indexable[T, U] {
def apply(value: T, index: Int): U
}
trait Sized[T] {
def size(value: T): Long
}
trait Headed[T, U] {
def head(value: T): U
}
trait Tailed[T] {
def tail(value: T): T
}
trait ConsUnapply[T, U] {
def unapply(x: T): Option[(U, T)]
}
object syntax {
implicit class IndexableOps[T, U](value: T)(implicit ev: Indexable[T, U]) {
def apply(index: Int): U = ev.apply(value, index)
}
implicit class SizedOps[T: Sized](value: T) {
def xSize: Long = implicitly[Sized[T]].size(value)
}
implicit class HeadedOps[T, U](value: T)(implicit ev: Headed[T, U]) {
def xHead: U = ev.head(value)
}
implicit class TailedOps[T: Tailed](value: T) {
def xTail: T = implicitly[Tailed[T]].tail(value)
}
implicit class ForeachableOps[T, U](value: T)(implicit ev: Foreachable[T, U]) {
def foreach(f: U ⇒ Any): Unit = ev.foreach(value, f)
}
}
object StreamInstances {
trait HasSize {
implicit def streamHasSize[T]: Sized[Stream[T]] = new Sized[Stream[T]] {
override def size(value: Stream[T]): Long = value.size
}
}
trait HasHead {
implicit def streamHasHead[T]: Headed[Stream[T], T] = new Headed[Stream[T], T] {
override def head(value: Stream[T]): T = value.head
}
}
trait HasTail {
implicit def streamHasTail[T]: Tailed[Stream[T]] = new Tailed[Stream[T]] {
override def tail(value: Stream[T]): Stream[T] = value.tail
}
}
}
object ArrayInstances {
trait HasForeach {
implicit def arrayHasForeachable[T]: Foreachable[Array[T], T] = new Foreachable[Array[T], T] {
import scala.Predef._
override def foreach(value: Array[T], f: (T) ⇒ Any): Unit = value.foreach(f)
}
}
trait HasIndexable {
implicit def arrayHasIndexable[T]: Indexable[Array[T], T] = new Indexable[Array[T], T] {
override def apply(value: Array[T], index: Int): T = value.apply(index)
}
}
trait HasSize {
implicit def arrayHasSize[T]: Sized[Array[T]] = new Sized[Array[T]] {
override def size(value: Array[T]): Long = value.length
}
}
trait HasHead {
implicit def arrayHasHead[T]: Headed[Array[T], T] = new Headed[Array[T], T] {
import scala.Predef._
override def head(value: Array[T]): T = value.head
}
}
trait HasTail {
implicit def arrayHasTail[T]: Tailed[Array[T]] = new Tailed[Array[T]] {
import scala.Predef._
override def tail(value: Array[T]): Array[T] = value.tail
}
}
trait HasConsUnapply {
implicit def arrayHasConsUnapply[T]: ConsUnapply[Array[T], T] = new ConsUnapply[Array[T], T] {
import scala.Predef._
override def unapply(x: Array[T]): Option[(T, Array[T])] = if(x.isEmpty) None else Some((x.head, x.tail))
}
}
}
object ListInstances {
private class ListTc[T] extends Sized[List[T]] with Headed[List[T], T] with Tailed[List[T]] {
override def size(value: List[T]): Long = value.size
override def head(value: List[T]): T = value.head
override def tail(value: List[T]): List[T] = value.tail
}
trait HasSize {
implicit def listHasSize[T]: Sized[List[T]] = new ListTc[T]
}
trait HasHead {
implicit def listHasHead[T]: Headed[List[T], T] = new ListTc[T]
}
trait HasTail {
implicit def listHasTail[T]: Tailed[List[T]] = new ListTc[T]
}
}
object ops {
trait `O(1)` extends ArrayInstances.HasSize
object `O(1)` extends `O(1)`
trait `O(N)`
extends `O(1)`
with ListInstances.HasSize
with ArrayInstances.HasForeach
with ArrayInstances.HasConsUnapply
object `O(N)` extends `O(N)`
trait NonTerminating extends `O(N)` with StreamInstances.HasSize
object NonTerminating extends NonTerminating
trait Partial
extends `O(N)`
with ArrayInstances.HasHead
with ArrayInstances.HasTail
with ListInstances.HasHead
with ListInstances.HasTail
with StreamInstances.HasHead
with StreamInstances.HasTail
with ArrayInstances.HasIndexable
object Partial extends Partial
trait All extends NonTerminating with Partial
object All extends All
}
object ::: {
def unapply[T, U](x: T)(implicit ev: ConsUnapply[T, U]): Option[(U, T)] =
ev.unapply(x)
}
object NNil {
def unapply[T](x: T)(implicit ev: Sized[T]): Boolean = ev.size(x) == 0
}
object Test {
import syntax._
import ops.`O(1)`._
Array(1,2,3).xSize
// List(1,2,3).xSize // does not compile
// Stream(1,2,3).xSize // does not compile
import ops.`O(N)`._
List(1,2,3).xSize // does compile due to the O(n) import
import ops.NonTerminating._
Stream(1,2,3).xSize // does compile due to the NonTerminating import
import ops.Partial._
Array(1,2,3).xHead
List(1, 2, 3).xHead
Stream(1,2,3).xHead
Array(1,2,3).xTail
List(1, 2, 3).xTail
Stream(1,2,3).xTail
}
object Test2 extends App {
import syntax._
import ops.All._
Array(1,2,3) match {
case x ::: y ⇒ println(s"$x $y")
case NNil() ⇒ println(s"Nope")
}
Array.empty[Int] match {
case x ::: y ⇒ println(s"$x $y")
case NNil() ⇒ println(s"Nope")
}
for(x ← Array(1,2,3))
println(x)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment