Is Reader monad the right approach to this ?

177 views
Skip to first unread message

Debasish Ghosh

unread,
Dec 17, 2010, 9:46:24 AM12/17/10
to sca...@googlegroups.com
Hi -

I have a bunch of functions that need *one* specific argument to be threaded through them. All these functions nicely compose together. But the problem is this *one* argument that I need to pass every time I compose these functions .. Here's the example ..

def f(a: A): (A, B) = { //..
def g(x: (A, B)): (A, C) = { //..
def h(y: (A, C)): D = { //..

The problem is this argument A, that I need to carry as inputs and outputs of these functions in order to make them compose. This A is effectively an environment that needs to be accessed within all these functions. Is Reader monad the way to model this situation ?

I came across this implementation of Reader monad in scalaz on SoF .. http://stackoverflow.com/questions/3284483/reader-monad-with-scalaz/3285028#3285028

How can this be idiomatically used to model the above scenario ? Or is there a better approach to this modeling ? Any help, pointers will be appreciated ..

Thanks.

Runar Bjarnason

unread,
Dec 17, 2010, 12:02:20 PM12/17/10
to sca...@googlegroups.com
Hi Debasish,

If you want your functions to have access to a shared environment
read-only, then the Reader monad is what you want. This works with
scalaz:

scala> val g: Int => String = _.toString
g: (Int) => String = <function1>

scala> val f: Int => Int = _ + 1
f: (Int) => Int = <function1>

scala> val e: Int => Boolean = _ % 2 == 0
e: (Int) => Boolean = <function1>

scala> for {
| x <- e
| y <- f
| z <- g
| }
| yield (x, y, z)
res2: (Int) => (Boolean, Int, String) = <function1>

scala> res2(3)
res3: (Boolean, Int, String) = (false,4,3)


If you want the functions to be able to read and write the
environment, then the monad you want is State:

scala> val fib = state((s:(Int, Int)) => ((s._2, s._1 + s._2), s._2))
fib: scalaz.State[(Int, Int),Int] = scalaz.States$$anon$1@4e1abb41

scala> Stream.continually(fib).take(10).sequence[({type
lam[x]=State[(Int, Int),x]})#lam, Int]
res30: scalaz.State[(Int, Int),scala.collection.immutable.Stream[Int]]
= scalaz.States$$anon$1@426a7e13

scala> res30 ! (0,1) toList
res31: List[Int] = List(1, 1, 2, 3, 5, 8, 13, 21, 34, 55)


This is equivalent to:
for { a1 <- fib; a2 <- fib; a3 <- fib; ... } yield List(a1, a2, a3, ...)

As you can see, the fib function both reads the state and modifies it
before it's fed to the next call to fib.


Runar

> --
> You received this message because you are subscribed to the Google Groups
> "scalaz" group.
> To post to this group, send email to sca...@googlegroups.com.
> To unsubscribe from this group, send email to
> scalaz+un...@googlegroups.com.
> For more options, visit this group at
> http://groups.google.com/group/scalaz?hl=en.
>

Debasish Ghosh

unread,
Dec 17, 2010, 2:25:16 PM12/17/10
to sca...@googlegroups.com
Excellent .. Thanks for the help!
Reply all
Reply to author
Forward
0 new messages