Note that there are some explanatory texts on larger screens.

plurals
  1. POHow to implement a reader monad to access a database
    text
    copied!<p>I try to implement a reader monad for the first time.</p> <p>I want to use monadic style to query the database.</p> <p>use case 1 : a user has a one-to-one relation with a colleague. Pseudo code is <code>getUserById(getUserById(id).getColleague())</code></p> <p>use case 2 : retrieve a list of users by id. Pseudo code is <code>List(getUserById(id1), getUserById(id2))</code></p> <p>It seems that this is good use cases for monads. My goal is to see if I can take advantage of monads to improve my code</p> <p>PS : Please provide at least one answer without scalaz.</p> <p>Here is the code :</p> <pre><code>package monad import com.mongodb.casbah.Imports._ object Monad { type UserId = Int case class User(id: UserId, name: String, colleagueId: UserId) trait Reader[I, A] { self =&gt; def run(id: I) : A def map[B](f: A =&gt; B) : Reader[I, B] = new Reader[I, B] { def run(id: I) = f(self.run(id)) } def flatMap[B](f: A =&gt; Reader[I, B]) : Reader[I, B] = new Reader[I, B] { def run(id: I) = f(self.run(id)).run(id) } } def coll = MongoClient()("test")("user") def DBObject2User(o: DBObject) : User = User(o.as[Double]("id").toInt, o.as[String]("name"), o.as[Double]("colleague").toInt) // Strange design, id is not used… def User2Colleague(u: User) : Reader[UserId, DBObject] = unit(coll.findOne(MongoDBObject("id" -&gt; u.colleagueId)).get) def GetUserById : Reader[UserId, DBObject] = Reader { id: UserId =&gt; coll.findOne(MongoDBObject("id" -&gt; id)).get } def GetUserById2 : Reader[UserId, User] = GetUserById.map(DBObject2User) def unit[A](a: =&gt; A) = Reader { id: UserId =&gt; a } object Reader { def apply[I, A](f: I =&gt; A) = new Reader[I, A] { def run(i: I) = f(i) } } def main(args: Array[String]) { // I can do println(GetUserById2.run(1)) // Same with for comprehension val userReader = for (io &lt;- GetUserById2) yield io println(userReader.run(1)) //Combination to explore one-to-one relation val user = GetUserById2.run(1) val colleague = GetUserById2.run(user.colleagueId) // Same with flatMap println(GetUserById2.flatMap(User2Colleague).run(1)) // Same with for-comprehension but doesn't work val io = for {io &lt;- GetUserById2 io2 &lt;- User2Colleague(io).map(DBObject2User)} yield io2 println(io.run(1)) //TODO: List[Reader] to Reader[List] } } </code></pre> <p>Is it the good way ? I have some doubt, cf my comment <code>Strange design</code></p> <p>How could I improve my code ?</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload