Skip to content

Instantly share code, notes, and snippets.

@davidpeklak
Last active August 29, 2015 14:01
Show Gist options
  • Save davidpeklak/e4aa2563ba1765eb033c to your computer and use it in GitHub Desktop.
Save davidpeklak/e4aa2563ba1765eb033c to your computer and use it in GitHub Desktop.
KleisliCombineDep
package smt.util
import scalaz.{Monad, Bind, Kleisli}
import scalaz.syntax.Ops
import scalaz.Kleisli._
import scalaz.Scalaz._
trait KleisliCombineDep {
type Logger
type Database
type Connection
type Data
type M[+A] // = e.g. Task[A]
implicit val MM: Monad[M]
def log(s: String): Kleisli[M, Logger, Unit]
val openConn: Kleisli[M, Database, Connection]
val closeConn: Kleisli[M, Connection, Unit]
val getData: Kleisli[M, Connection, Data]
case class DbL(db: Database, log: Logger)
/**
* let this do the following:
* 1) openConn
* 2) log about it!
* 3) getData
* 4) log about it!
* 5) closeConn
* 6) log about it!
*/
val openConnAndGetData: Kleisli[M, DbL, Data] = {
case class CL(conn: Connection, log: Logger)
def cl(dbl: DbL, conn: Connection): CL = CL(conn, dbl.log)
val syn = KleisliHärte.kleisliSyntax[M, DbL]
import syn._
val openConnAndLog: Kleisli[M, DbL, Connection] = for {
c <- openConn.local[DbL](_.db)
_ <- log("Opened connection").local[DbL](_.log)
} yield c
val getDataAndLog: Kleisli[M, CL, Data] = for {
d <- getData.local[CL](_.conn)
_ <- log("Got data").local[CL](_.log)
} yield d
val closeConnAndLog: Kleisli[M, CL, Unit] = for {
_ <- closeConn.local[CL](_.conn)
_ <- log("Closed conneection").local[CL](_.log)
} yield ()
openConnAndLog >=! cl !=> {
for {
d <- getDataAndLog
_ <- closeConnAndLog
} yield d
}
}
}
object KleisliHärte {
trait KleisliOps[M[+ _],A, B] extends Ops[Kleisli[M, A, B]] {
trait Combining[AB] {
val bc: Bind[M]
val ccc: (A, B) => AB
def !=>[C](k: Kleisli[M, AB, C]): Kleisli[M, A, C] = kleisli((a: A) => bc.bind(self(a))(b => k(ccc(a, b))))
}
def >=!>[AB, C](cc: (A, B) => AB)(k: Kleisli[M, AB, C])(implicit b: Bind[M]): Kleisli[M, A, C] = kleisli((a: A) => b.bind(self(a))(b => k(cc(a, b))))
def >=![AB](cc: (A, B) => AB)(implicit b: Bind[M]): Combining[AB] = new Combining[AB] {
val bc = b
val ccc = cc
}
}
trait KleisliSyntax[M[+ _], A] {
implicit def toKleisliOps[B](v: Kleisli[M, A, B]): KleisliOps[M, A, B] = new KleisliOps[M, A, B] {
val self = v
}
}
def kleisliSyntax[M[+ _], A]: KleisliSyntax[M, A] = new KleisliSyntax[M, A] {}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment