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)) } }