Skip to content

Instantly share code, notes, and snippets.

@gwenzek
Last active August 29, 2015 14:07
Show Gist options
  • Save gwenzek/123fc48c83d3da9a0fda to your computer and use it in GitHub Desktop.
Save gwenzek/123fc48c83d3da9a0fda to your computer and use it in GitHub Desktop.
playing with implicit in scala
import evidence._
object animal {
trait Animal
trait Car
trait Cow extends Animal
type MooMoo = Cow
implicitly[ComponentOf[Cow, Cow]]
implicitly[ComponentOf[Cow, MooMoo]]
implicitly[ComponentOf[Cow, Cow || Car]]
implicitly[ComponentOf[Cow, Car || Cow]]
implicitly[ComponentOf[Cow, Car || Animal || Cow]]
implicitly[ConformsTo[Cow, Animal]]
implicitly[ConformsTo[Cow, Animal || Car]]
implicitly[ConformsTo[Cow, Car || Animal]]
implicitly[ConformsTo[Cow, Animal || Car || String]]
// failing a Cow isn't a Car
// implicitly[ConformsTo[Cow, Car || Car]]
// implicitly[ConformsTo[Cow, Car]]
trait Barking
trait Dog extends Animal with Barking
// implicitly[Minus[Dog, Animal, Nothing]] <==> Dog - Animal is Nothing
implicitly[Minus[Dog, Animal, Nothing]]
implicitly[Minus[Dog, Barking, Nothing]]
implicitly[Minus[Cow, Barking, Cow]]
implicitly[Minus[Cow, Animal with Barking, Cow]]
implicitly[Minus[Dog || Cow, Barking, Cow]]
implicitly[Minus[Cow || Dog, Barking, Cow]]
implicitly[Minus[Cow || Car, Barking, Cow || Car]]
}
package object evidence {
type ||[A, B] = Either[A, B]
trait SupportingEvidence
/** C is an Atom and U==C or U is a type union explicitly containing C */
class ComponentOf[C, U] extends SupportingEvidence
final class Atom[T] extends ComponentOf[T, T]
object ComponentOf{
implicit def atom[T](implicit ev: Not[T <:< ||[_,_]]) = nothingIsNothing.asInstanceOf[Atom[T]]
implicit def leftComponent[A, B, C](implicit ev: C ComponentOf A): C ComponentOf (A || B) =
ev.asInstanceOf[C ComponentOf (A || B)]
implicit def rightComponent[A, B, C](implicit ev: C ComponentOf B, but: Not[C ComponentOf A]): C ComponentOf (A || B) =
ev.asInstanceOf[C ComponentOf (A || B)]
val nothingIsNothing = new Atom[Nothing]
}
// implicit def inheritFrom[X <: Y, Y](x: X): X ComponentOf Y = new ComponentOf[X, Y]();
// implicit def directlyInheritFrom[X, Y](implicit ev: X <:< Y): X ComponentOf Y = new ComponentOf[X, Y]();
/** T = U - C, calculated as follows:
* U = A || B => A - C || B - C
* U <: C => Nothing
* else => U
*/
final class Minus[U, C, T] extends SupportingEvidence
object Minus {
implicit def nothing[U, C](implicit atom: Atom[U], conforms: U ConformsTo C): Minus[U, C, Nothing] =
certify[U, C, Nothing]
implicit def self[U, C](implicit atom: Atom[U], diff: Not[U ConformsTo C]): Minus[U, C, U] =
certify[U, C, U]
implicit def left[A, B, C, T](implicit left: Minus[A, C, T],
leftSomething: Not[A ConformsTo C],
rightNothing: B ConformsTo C): Minus[A || B, C, T] =
certify[A || B, C, T]
implicit def right[A, B, C, T](implicit leftNothing: A ConformsTo C,
right: Minus[B, C, T]): Minus[A || B, C, T] =
certify[A || B, C, T]
implicit def union[A, B, C, L, R](implicit //atom: Atom[C],
leftSomething: Not[A ConformsTo C],
rightSomething: Not[B ConformsTo C],
left: Minus[A, C, L],
right: Minus[B, C, R]): Minus[A || B, C, L || R] =
certify[A || B, C, L || R]
def certify[U, C, T] = nothingMinusNothingIsNothing.asInstanceOf[Minus[U, C, T]]
val nothingMinusNothingIsNothing = new Minus[Nothing, Nothing, Nothing]
}
class ConformsTo[-X, +Y](val cast: X => Y) extends SupportingEvidence
object ConformsTo {
def apply[X, Y](fun: X=>Y): ConformsTo[X, Y] = new ConformsTo(fun)
implicit def directlyConformsTo[X, Y](implicit ev: X <:< Y): ConformsTo[X, Y] =
ConformsTo(ev.apply _)
implicit def conformsToLeft[X, A, B](implicit atom: Atom[X],
conform: ConformsTo[X, A],
only: Not[ConformsTo[X, B]]): ConformsTo[X, A || B] =
ConformsTo((x: X) => Left(conform.cast(x)))
implicit def conformsToRight[X, A, B](implicit atom: Atom[X],
conform: ConformsTo[X, B],
only: Not[ConformsTo[X, A]]): ConformsTo[X, A || B] =
ConformsTo((x: X) => Right(conform.cast(x)))
implicit def conformsToBoth[X, A, B](implicit atom: Atom[X],
left: ConformsTo[X, A],
right: ConformsTo[X, B]): ConformsTo[X, A || B] =
ConformsTo((x: X) => Left(left.cast(x)))
implicit def alternativesConform[A, B, Y](implicit left: ConformsTo[A, Y], right: ConformsTo[B, Y],
nonDirect: Not[(A || B) <:< Y]): ConformsTo[A || B, Y] =
ConformsTo((x: A || B) => x match {
case Left(l) => left.cast(l)
case Right(r) => right.cast(r)
})
}
/** Implicit value for Not[T] exists <=> there's no implicit value for T in scope */
final class Not[+T](override val toString: String)
object Not {
val nice = new Not[Nothing]("default")
val mean = new Not[Nothing]("conflict")
implicit def conflict[T](implicit ev: T): Not[T] = Not.mean
implicit def default[T]: Not[T] = Not.nice
}
type Something[X] = Not[X <:< Nothing]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment