Created
June 6, 2012 03:53
-
-
Save blouerat/2879800 to your computer and use it in GitHub Desktop.
Reader Monad
This file contains hidden or 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
/* | |
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