Skip to content

Instantly share code, notes, and snippets.

@drdozer
Created February 20, 2015 20:42
Show Gist options
  • Save drdozer/e01cdcd5c856d33378dc to your computer and use it in GitHub Desktop.
Save drdozer/e01cdcd5c856d33378dc to your computer and use it in GitHub Desktop.
import simulacrum._
import scala.annotation.implicitNotFound
@implicitNotFound("Could not find constructor for ${T} that takes a single argument of ${A}")
trait Constructor1[+T, -A] {
def apply(a: A): T
}
@implicitNotFound("Could not find destructor for ${T} that decomposes into a single argument of ${A}")
trait Destructor1[-T, +A] {
def unapply(t: T): Option[A]
}
trait Companion1[T, A] extends Constructor1[T, A] with Destructor1[T, A] {
def apply(a: A): T
def unapply(t: T): Option[A]
}
trait Companion2[T, A, B] {
def apply(a: A, b: B): T
def unapply(t: T): Option[(A, B)]
}
trait Companion3[T, A, B, C] {
def apply(a: A, b: B, c: C): T
def unapply(t: T): Option[(A, B, C)]
}
trait Companion4[T, A, B, C, D] {
def apply(a: A, b: B, c: C, d: D): T
def unapply(t: T): Option[(A, B, C, D)]
}
@typeclass trait Companion_*[T[_]] {
def apply[A](as: A*): T[A]
def unapply[A](ta: T[A]): Option[Seq[A]]
}
@implicitNotFound("Could not find hint for constructing ${A} -> ${B} -> ${C}")
trait ConstructorHint[A, B, C]
trait Cstr[α] {
type λ[β] = ConstructorChain[β, α]
}
@implicitNotFound("Could not build a constructor chain from ${S} to ${T}")
trait ConstructorChain[-S, +T] extends Function1[S, T] {
def apply(s: S): T
}
object ConstructorChain extends ConstructorChain1 {
implicit def fromCast[S, T](implicit ev: S <:< T): ConstructorChain[S, T] = new ConstructorChain[S, T] {
override def apply(a: S): T = a
}
}
trait ConstructorChain1 extends ConstructorChain2 {
implicit def fromConstructor1[S, T](implicit
c1: Constructor1[T, S]): ConstructorChain[S, T] = new ConstructorChain[S, T] {
override def apply(a: S): T = c1.apply(a)
}
}
trait ConstructorChain2 {
implicit def chain[R, S, T](implicit
ch: ConstructorHint[R, S, T],
bt: ConstructorChain[S, T],
ab: ConstructorChain[R, S]): ConstructorChain[R, T] = new ConstructorChain[R, T] {
override def apply(r: R) = bt.apply(ab.apply(r))
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment