Skip to content

Instantly share code, notes, and snippets.

@blouerat
Created June 6, 2012 03:53
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save blouerat/2879800 to your computer and use it in GitHub Desktop.
Save blouerat/2879800 to your computer and use it in GitHub Desktop.
Reader Monad
/*
Based on the first part of the talk "Dead-Simple Dependency Injection in Scala" by @runarorama at NEScala 2012
http://marakana.com/s/dependency_injection_in_scala,1108/index.html
*/
class Connection {
def prepareStatement(query: String) = new Statement()
}
class Statement {
def setString(i: Int, str: String): Unit = {}
def executeUpdate(): Unit = {}
def close(): Unit = {}
}
case class Reader[C, A](g: C => A) {
def apply(c: C) = g(c)
def map[B](f: A => B): Reader[C, B] = Reader(c => f(g(c)))
def flatMap[B](f: A => Reader[C, B]): Reader[C, B] = Reader(c => f(g(c))(c))
}
def pure[C, A](a: A): Reader[C, A] = Reader(c => a)
implicit def reader[A,B](f: A => B) = Reader(f)
abstract class ConnProvider {
def apply[A](f: Reader[Connection, A]): A
}
def mkProvider(driver: String, url: String) =
new ConnProvider {
def apply[A](f: Reader[Connection, A]): A = {
f(new Connection)
}
}
def setUserPwd(id: String, pwd: String): Reader[Connection, Unit] =
for {
stmt <- Reader[Connection, Statement](c => c.prepareStatement("query"))
_ <- pure[Connection, Unit](stmt.setString(1, pwd))
_ <- pure[Connection, Unit](stmt.setString(2, id))
_ <- pure[Connection, Unit](stmt.executeUpdate())
_ <- pure[Connection, Unit](stmt.close())
} yield()
def getUserPwd(id: String) = pure[Connection, String]("foo")
def changePwd(userId: String, oldPwd: String, newPwd: String): Reader[Connection, Boolean] =
for {
pwd <- getUserPwd(userId)
eq <- if(pwd == oldPwd) for {
_ <- setUserPwd(userId, newPwd)
} yield true
else pure[Connection, Boolean](false)
} yield eq
def myProgram(userid: String): ConnProvider => Unit =
r => {
println("Enter old password")
val oldPwd = readLine()
println("Enter new password")
val newPwd = readLine()
r(changePwd(userid, oldPwd, newPwd))
}
lazy val fooDB = mkProvider("foo", "foo://foo")
lazy val barDB = mkProvider("bar", "bar://bar")
def runInFoo[A](f: ConnProvider => A): A = f(fooDB)
def runInBar[A](f: ConnProvider => A): A = f(barDB)
def main(userid: String) = runInFoo(myProgram(userid))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment