On Github danielbedo / readermonad
scala> val f = (i: Int) => i*3 f: Int => Int = <function1>
f: Int => Int is just a fancy way of saying Function1[Int, Int]
<span style="font-family: monospace;"> def andThen[A](g: R => A): T1 => A = { x => g(apply(x)) }</span><br>
scala> val f = (i: Int) => i*3 f: Int => Int = <function1> scala> val g = (i: Int) => i.toString g: Int => String = <function1>scala<span>> </span><span style="font-family: monospace;">val tripleToString = f andThen g</span>tripleToString: Int => String = <function1><br>scala> tripleToString(2) res0: String = 6<br>
scala> import scalaz.Reader import scalaz.Reader scala> val f = Reader((i: Int) => i*3) f: scalaz.Reader[Int,Int] = scalaz.KleisliFunctions$$anon$17@53628ee
val g = f map (i => i + 2) val h = for (i <- g) yield i.toString
<font style="font-size: 18px;">trait Users {
def getUser(id: Int) = Reader((userRepository: UserRepository) =>
userRepository.get(id)
)
def findUser(username: String) = Reader((userRepository: UserRepository) =>
userRepository.find(username)
)
}</font>
I'm gonna return a User, when I get a UserRepository
The actual injection is deferred
object UserInfo extends Users {<br> def userEmail(id: Int) = {
getUser(id) map (_.email)
}
def userInfo(username: String) =
for {
user <- findUser(username)
boss <- getUser(user.supervisorId)
} yield Map(
"fullName" -> s"${user.firstName} ${user.lastName}",
"email" -> s"${user.email}",
"boss" -> s"${boss.firstName} ${boss.lastName}"
)}
but we don't have to mention the Repository anywhere except our primitive Readers
trait Repositories {
def userRepository: UserRepository
def questionRepository: QuestionRepository
}
trait Users {
def getUser(id: Int) = Reader((repos: Repositories) =>
repos.userRepository.get(id)
)
}
object Application extends Application(UserRepositoryImpl)
class Application(userRepository: UserRepository) with Users {
def getUserEmail(id: Int) = Action {
HttpOk(UserInfo.userEmail(id)(userRepository))
}
}
object Application extends Application with UserRepositoryComponentImpl
trait Application extends Controller with Users {
this: UserRepositoryComponent =>
def getUserEmail(id: Int) = Action {
HttpOk(UserInfo.userEmail(id)(userRepository))
}
}