Skip to content

Instantly share code, notes, and snippets.

@shinnya
Last active September 10, 2017 06:22
Show Gist options
  • Save shinnya/8309283 to your computer and use it in GitHub Desktop.
Save shinnya/8309283 to your computer and use it in GitHub Desktop.
Reader Monad
/*
* Copyright (C) 2017 Shinya Yamaoka
* Licensed under the MIT License.; you may not use this file except in
* compliance with the license. You may obtain a copy of the License at
* https://opensource.org/licenses/mit-license.php
*/
object ReaderMonad {
class Reader[-E, +R] private (g: E => R) {
def apply(env: E): R = g(env)
def map[A](f: R => A): Reader[E, A] = new Reader[E, A](env => f(g(env)))
def flatMap[A, B <: E](f: R => Reader[B, A]): Reader[B, A] = new Reader[B, A](env => f(g(env))(env))
}
def pure[E, R](v: R): Reader[E, R] = Reader.pure(v)
def ask[E]: Reader[E, E] = Reader.ask
private[this] object Reader {
def pure[E, R](v: R): Reader[E, R] = new Reader[E, R](_ => v)
def ask[E]: Reader[E, E] = new Reader[E, E](identity)
}
}
object Main {
import ReaderMonad._
case class User(id: Int)
trait UserRepository {
def find(id: Int): Option[User]
}
object UserRepository extends UserRepository {
private[this] val users = Map(1 -> User(1))
def find(id: Int): Option[User] = users.get(id)
}
sealed trait AuthResult
case class Success(user: User) extends AuthResult
case class Failure(message: String) extends AuthResult
case class Authenticator(repository: UserRepository) {
def authenticate(username: String, password: String): Reader[Int, AuthResult] = for {
userId <- ask
} yield {
if (isValid(username, password)) {
repository find(userId) map (Success(_)) getOrElse Failure("The user doesn't exist.")
} else {
Failure("Incorrect username or password.")
}
}
def isValid(username: String, password: String): Boolean = true
}
def main(args: Array[String]): Unit = {
val authenticator = new Authenticator(UserRepository)
val readerForUser1 = authenticator.authenticate("hoge", "")
val readerForUser2 = authenticator.authenticate("fuba", "")
println(readerForUser1(1))
println(readerForUser2(2))
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment