Created
February 9, 2021 20:12
-
-
Save chrislewis/a0298bbae8f1842bf0f0652766fa030d to your computer and use it in GitHub Desktop.
An encoding of typesafe and dynamic composition of a finite set of behaviors
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.implicitConversions | |
/** | |
* A hypothetical type that may possess any combination of several properties, each encoded as a trait specifying | |
* that property. Our example type may have any of these properties: | |
* | |
* links: Set[String] | |
* meta: Map[String, String] | |
* other: Int | |
* another: String | |
*/ | |
sealed trait Rel | |
sealed trait WithLinks extends Rel { | |
def links: Set[String] | |
} | |
sealed trait WithMeta extends Rel { | |
def meta: Map[String, String] | |
} | |
sealed trait WithOther extends Rel { | |
def other: Int | |
} | |
sealed trait WithAnother extends Rel { | |
def another: String | |
} | |
/** | |
* A simple container type to hold a value, which itself may be a property or a property composed with | |
* another container. | |
*/ | |
trait One[A] { | |
def value: A | |
} | |
object One { | |
/** Us a container of A as an A. */ | |
implicit def oneToA[A](one: One[A]): A = one.value | |
/** Us a container of a container of A as an A. */ | |
implicit def oneToA2[A, R](one: One[One[A] with R]): A = one.value.value | |
/** Us a container of a container of a container of A as an A. */ | |
implicit def oneToA3[A, R, RR](one: One[One[One[A] with RR] with R]): A = one.value.value.value | |
} | |
/** | |
* Builder functions to construct various compositions of behavior. | |
* | |
* val wl = Rel.withLinks(Set("fake")) | |
* val wlm = Rel.withMeta(wl, Map("one" -> "1")) | |
* val wlmo = Rel.withOther(wlm, 1) | |
* val wlmoa = Rel.withAnother(wlmo, "hi") | |
*/ | |
object Rel { | |
def withLinks(_links: Set[String]): WithLinks = new WithLinks { | |
override def links: Set[String] = _links | |
} | |
def withMeta[R <: Rel](rel: R, _meta: Map[String, String]): One[R] with WithMeta = new One[R] with WithMeta { | |
override def value: R = rel | |
override def meta: Map[String, String] = _meta | |
} | |
def withOther[R <: Rel](rel: R, _other: Int): One[R] with WithOther = new One[R] with WithOther { | |
override def value: R = rel | |
override def other: Int = _other | |
} | |
def withAnother[R <: Rel](rel: R, _another: String): One[R] with WithAnother = new One[R] with WithAnother { | |
override def value: R = rel | |
override def another: String = _another | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment