Construction with Effects
sourceobject Effects {
type Id[A] = A
final class Document(private var name: String) {
import Document._
private object capabilities {
val nameChanger: NameChanger[Id] = new NameChanger[Id] {
override def changeName(newName: String): Unit = {
name = newName
}
}
}
override def toString: String = s"Document($name)"
}
object Document {
trait NameChanger[F[_]] {
def changeName(name: String): F[Unit]
}
trait WithEffect[C[_[_]], F[_]] {
def apply(capability: C[Id]): C[F]
}
// The default "no effect" type Id[A] = A
implicit val idEffect: NameChanger WithEffect Id = new WithEffect[NameChanger, Id] {
override def apply(capability: NameChanger[Id]): NameChanger[Id] = identity(capability)
}
// Apply a "Try" effect to the capability
implicit val tryEffect: NameChanger WithEffect Try = new WithEffect[NameChanger, Try] {
override def apply(capability: NameChanger[Id]): NameChanger[Try] = new NameChanger[Try] {
override def changeName(name: String): Try[Unit] = Try(capability.changeName(name))
}
}
class Access {
def nameChanger[F[_]](
doc: Document
)(implicit ev: NameChanger WithEffect F): NameChanger[F] = {
val effect = implicitly[NameChanger WithEffect F]
effect(doc.capabilities.nameChanger)
}
}
}
def main(args: Array[String]): Unit = {
val document = new Document("will")
val access = new Document.Access()
val tryNameChanger = access.nameChanger[Try](document)
tryNameChanger.changeName("steve") match {
case Success(_) =>
println(s"result = $document")
case Failure(ex) =>
println(s"exception = $ex")
}
// or...
val idNameChanger = access.nameChanger[Id](document)
idNameChanger.changeName("Will")
println(s"result = $document")
}
}
The source code for this page can be found here.