Skip to content

Instantly share code, notes, and snippets.

@metasim
Created June 11, 2016 21:04
Show Gist options
  • Select an option

  • Save metasim/916bb473aed5b7e6daea83ebf87037d1 to your computer and use it in GitHub Desktop.

Select an option

Save metasim/916bb473aed5b7e6daea83ebf87037d1 to your computer and use it in GitHub Desktop.
import scala.reflect.runtime.universe._
sealed trait not[-A] {}
type union[A,B] = {
type prove[Z] = not[not[Z]] <:< not[not[A] with not[B]]
}
type Tagged[U] = { type Tag = U }
type @@[T, U] = T with Tagged[U]
case class Transformed(state: Boolean, value: String)
trait ADomain
trait BDomain
// https://coderwall.com/p/l-plmq/adding-semantic-to-base-types-parameters-in-scala
type A = String @@ ADomain
type B = String @@ BDomain
implicit class TaggedInt(val s: String) extends AnyRef {
def asA = s.asInstanceOf[A]
def asB = s.asInstanceOf[B]
}
type ATransformed = A ⇒ Transformed
type BTransformed = B ⇒ Transformed
type AtoB = A ⇒ B
type BtoA = B ⇒ A
implicit class EnrichA(a: AtoB) {
def grow(n: Int): BtoA = (a andThen (_ * n)).asInstanceOf[BtoA]
}
implicit class EnrichB(a: BtoA) {
def shrink(n: Int): AtoB = (a andThen (_ drop n)).asInstanceOf[AtoB]
}
implicit class EnrichAorB[T: union[AtoB, BtoA]#prove: TypeTag](aorb: T) {
val tpe = implicitly[TypeTag[T]]
def trans(b: Boolean) = (aorb match {
case f: AtoB @unchecked if tpe == typeTag[AtoB] ⇒ f andThen {s ⇒ Transformed(b, if(b) s.toUpperCase else s.toLowerCase)}
case f: BtoA @unchecked if tpe == typeTag[BtoA] ⇒ f andThen {s ⇒ Transformed(b, if(!b) s.toUpperCase else s.toLowerCase)}
}).asInstanceOf[String ⇒ Transformed]
}
val Start: AtoB = (a: A) ⇒ a.asInstanceOf[B]
val valid1 = Start grow 3 shrink 2 trans true
val valid2 = Start grow 3 shrink 2 grow 2 trans true
//val invalid1 = Start shrink 2 grow 2
//val invalid2 = Start grow 2 grow 3
valid1("blah".asA)
valid2("boo".asA)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment