Last active
May 25, 2017 19:05
-
-
Save rudogma/44f1cf5ab56cb7f77c403d2bc113f5d0 to your computer and use it in GitHub Desktop.
Tagging example for Folex
This file contains 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 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) | |
} | |
} |
This file contains 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 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