Skip to content

Instantly share code, notes, and snippets.

@tyrcho
Created July 26, 2017 19:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tyrcho/c6ffc98afb65ce86031c4711661884a8 to your computer and use it in GitHub Desktop.
Save tyrcho/c6ffc98afb65ce86031c4711661884a8 to your computer and use it in GitHub Desktop.
import java.sql.{Connection, DriverManager}
import scala.io.StdIn._
object FreeMonads {
def getUserPwd(id: String)(c: Connection): String = {
""
}
def setUserPwd(id: String, pwd: String)(c: Connection): Unit = {
val stmt = c.prepareStatement("update users set pwd = ? where id = ?")
stmt.setString(1, pwd)
stmt.setString(2, id)
stmt.executeUpdate
stmt.close()
}
case class DB[A](g: Connection => A) {
def apply(c: Connection): A = g(c)
def map[B](f: A => B): DB[B] =
DB(c => f(g(c)))
def flatMap[B](f: A => DB[B]): DB[B] =
DB(c => f(g(c))(c))
}
def pureDB[A](a: A): DB[A] = DB(_ => a)
implicit def db[A](f: Connection => A): DB[A] = DB(f)
def changePwd(userid: String, oldPwd: String, newPwd: String): DB[Boolean] =
for {pwd <- getUserPwd(userid)
eq <-
if (pwd == oldPwd) for {_ <- setUserPwd(userid, newPwd)} yield true
else pureDB(false)
} yield eq
abstract class ConnProvider {
def apply[A](f: DB[A]): A
}
def mkProvider(driver: String, url: String) =
new ConnProvider {
def apply[A](f: DB[A]): A = {
Class.forName(driver)
val conn = DriverManager.getConnection(url)
try {
f(conn)
} finally {
conn.close()
}
}
}
lazy val sqliteTestDB: ConnProvider = mkProvider("org.sqlite.JDBC", "jdbc:sqlite::memory:")
lazy val mysqlProdDB: ConnProvider = mkProvider("org.gjt.mm.mysql.Driver", "jdbc:mysql://prod:3306/?user=one&password=two")
def myProgram(userid: String)(r: ConnProvider): Unit = {
println("Enter old password")
val oldPwd = readLine()
println("Enter new password")
val newPwd = readLine()
r(changePwd(userid, oldPwd, newPwd))
}
def runInTest[A](f: ConnProvider => A): A = f(sqliteTestDB)
def runInProduction[A](f: ConnProvider => A): A = f(mysqlProdDB)
def main(args: Array[String]): Unit = runInTest(myProgram(args(0)))
case class Reader[C, A](g: C => A) {
def apply(c: C): A = 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 pureReader[C, A](a: A): Reader[C, A] = Reader(_ => a)
implicit def funToReader[C, A](read: C => A): Reader[C, A] = Reader(read)
trait KeyValueStore {
def put(key: String, value: String): Unit
def get(key: String): String
def delete(key: String): Unit
}
def modify(k: String, f: String => String): Reader[KeyValueStore, Unit] =
for {
v <- _.get(k)
_ <- _.put(k, f(v))
} yield ()
}
@tyrcho
Copy link
Author

tyrcho commented Jul 26, 2017

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment