Skip to content

Instantly share code, notes, and snippets.

@rudogma
Last active May 25, 2017 19:05
Show Gist options
  • Save rudogma/44f1cf5ab56cb7f77c403d2bc113f5d0 to your computer and use it in GitHub Desktop.
Save rudogma/44f1cf5ab56cb7f77c403d2bc113f5d0 to your computer and use it in GitHub Desktop.
Tagging example for Folex
import scala.language.higherKinds
package object tag {
private def cast[T, U](v: U): T = v.asInstanceOf[T]
type Tag[T, +U] = {type Raw = T ; type Gag <: U }
type @@[T, +U] = T with Tag[T, U]
type Tagged[T, +U] = T with Tag[T, U]
def tag[T, U](value:T):T @@ U = cast(value)
trait TaggedType[T] {
sealed trait Tag
type Raw = T
type Type = T @@ Tag
def apply(raw: T): T @@ Tag = cast(raw)
}
//For adding tag at toplevel
implicit class TopLevelTagger[T](val value: T) {
def @@(typ: TaggedType[T]): T @@ typ.Tag = cast(value)
}
//For changing tag
implicit class TopLevelChangeTagger[T,U](val value: Tag[T,U]) {
def @@(typ: TaggedType[T]): T @@ typ.Tag = cast(value)
}
/**
* Using `@@@` instead of `@@` because of Intellij Idea losts autocomplete at toplevel tagging
* and marks with `red` (compiles, but annoying and not usable)
*/
//For adding tag at `type bound` level
implicit class TypeBoundTagger[F[_], T](val value: F[T]) {
def @@@(typ: TaggedType[T]): F[T @@ typ.Tag] = cast(value)
}
//For changing tag at `type bound` level
implicit class TypeBoundChangeTagger[F[_], T, U](val value: F[T @@ U]) {
def @@@(typ: TaggedType[T]): F[T @@ typ.Tag] = cast(value)
}
}
import cats.data.Ior
import tag._
object UserRelations {
object IsFollower extends TaggedType[Boolean]
type IsFollower = IsFollower.Type
object IsFollowing extends TaggedType[Boolean]
type IsFollowing = IsFollowing.Type
type Rel = Ior[IsFollowing, IsFollower]
implicit class OptionTagOps[U, I](opt: Option[U with Tag[U,I]]) {
def getOrElseT(default: U): U @@ I = {
opt.getOrElse(tag[U, I](default))
}
}
val example1 = Ior.left(IsFollower(true)).left.getOrElseT(false) //works fine
val casted1: IsFollower = example1 //works fine
val example2: IsFollower = Ior.left(IsFollower(true)).left.getOrElseT(false) //now works fine
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment