Skip to content

Instantly share code, notes, and snippets.

@yannick-cw
Last active August 13, 2017 15:02
Show Gist options
  • Save yannick-cw/2ad9ede65acf6b56343d1e4430a3b4ff to your computer and use it in GitHub Desktop.
Save yannick-cw/2ad9ede65acf6b56343d1e4430a3b4ff to your computer and use it in GitHub Desktop.
Examples with two phantom types patterns
object DbRepo {
sealed trait State
sealed trait Fresh extends State
sealed trait IndexCreated extends State
sealed trait IndexReady extends State
sealed trait ReadyToRead extends State
def apply(): DbRepo[Fresh] = new DbRepo
}
class DbRepo[RepoState <: DbRepo.State] private {
import DbRepo._
def readDoc(id: String)(implicit ev: RepoState =:= IndexReady): Future[(String, DbRepo[IndexReady])] = {
println("fetching document ...")
Future.successful(("theDoc", new DbRepo))
}
def writeDocument(doc: String)(implicit ev: RepoState =:= IndexReady): Future[DbRepo[IndexReady]] = {
println("indexing ...")
Future.successful(new DbRepo)
}
def addMappingSettings(mapping: String)(implicit ev: RepoState =:= IndexCreated): Future[DbRepo[IndexReady]] = {
println("adding mapping")
Future.successful(new DbRepo)
}
def createIndex(name: String)(implicit ev: RepoState =:= Fresh): Future[DbRepo[IndexCreated]] = {
println("creating index")
Future.successful(new DbRepo)
}
}
object Indexing extends App {
val doc1 = for {
created <- DbRepo().createIndex("testIndex")
ready <- created.addMappingSettings("test mapping")
written <- ready.writeDocument("Hi")
(doc, index) <- written.readDoc("id1")
} yield doc
doc1.foreach(println)
// creating index
// adding mapping
// indexing ...
// fetching document ...
// "theDoc"
DbRepo().writeDocument("not gonna work")
// Cannot prove that DbRepo.Fresh =:= DbRepo.IndexReady
}
object LoanPhantoms {
case class LoanApplication[Status] private[Loans] (
name: String,
actualRepaymentYears: Option[Int] = None,
info: Option[String] = None
)
trait Applied
trait Approved
trait Enriched
type LoanApplied = LoanApplication[Applied]
type LoanApproved = LoanApplication[Approved]
type LoanEnriched = LoanApplication[Enriched]
def applyLoan(name: String): LoanApplication[Applied] = LoanApplication[Applied](name)
def approve: Kleisli[Option, LoanApplied, LoanApproved] =
Kleisli(l => Some(l.copy(actualRepaymentYears = Some(12))))
def enrich: Kleisli[Option, LoanApproved, LoanEnriched] =
Kleisli(l => Some(l.copy(info = Some("enriched it"))))
val l: LoanApplication[Applied] = applyLoan("me")
val op: Kleisli[Option, LoanApplied, LoanEnriched] = approve andThen enrich
val loan: Option[LoanEnriched] = op run l
// val nop = enrich andThen approve
// doesn't compile
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment