Last active
August 29, 2015 14:07
-
-
Save gwenzek/123fc48c83d3da9a0fda to your computer and use it in GitHub Desktop.
playing with implicit in scala
This file contains hidden or 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
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]] | |
} |
This file contains hidden or 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
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
created in answer to:
http://stackoverflow.com/questions/26362459/implicit-resolution-and-their-parameter-type-inference-in-scala