Reader Monad [Video]

282 views
Skip to first unread message

Tony Morris

unread,
Mar 6, 2011, 7:20:33 PM3/6/11
to scala-user
http://vimeo.com/20674558

The cameraman has told me that the batteries went flat through the
second talk (Writer monad), sorry.

--
Tony Morris
http://tmorris.net/


Vlad Patryshev

unread,
Mar 31, 2011, 8:46:37 PM3/31/11
to tmo...@tmorris.net, Tony Morris, scala-user
At last watched it. Thank you! Kind of opened my eyes; written in
Haskell, I just could not get the meaning of it.

Well, categorically it is formulated the simplest way: T^Env, with
const as unit and curry of the diagonal as join.

Used the notion immediately in my, hmm, java code, for sessions dependency.

Thanks,
-Vlad

Chris Twiner

unread,
Apr 1, 2011, 8:21:13 AM4/1/11
to Vlad Patryshev, tmo...@tmorris.net, Tony Morris, scala-user
Same deal, great talk, its a shame the end scala example (the extra 30
minutes down the pub time) wasn't covered though.

That example slide really pulls it all together.

Eric Le Goff

unread,
Apr 1, 2011, 9:47:34 AM4/1/11
to Chris Twiner, scala-user
On Fri, Apr 1, 2011 at 2:21 PM, Chris Twiner <chris....@gmail.com> wrote:
Same deal, great talk, its a shame the end scala example (the extra 30
minutes down the pub time) wasn't covered though.

That example slide really pulls it all together.

I was also enlightened by this presentation. BTW You can directly jump to the above mentioned slide here :

It really helps former imperative language developers like me.

Eric


Razvan Cojocaru

unread,
Apr 1, 2011, 9:56:35 AM4/1/11
to Eric Le Goff, scala-user

“former” ? Lucky you!

bblfish

unread,
Dec 6, 2011, 5:13:28 AM12/6/11
to scala...@googlegroups.com, tmo...@tmorris.net
I Tony,

     thanks for this great intro to Reader Monads [1]  I went through the presentation, watched the video, and bought the mug. ;-) 
But I have a few questions remaining. 

1)  You start your talk by saying that one can solve the following problem

Let's pass the configuration to every function that requires it, including those for which it is simply passed on.
 
Indeed that is exactly the type of problem I had with Read-Write-Web project I am working on [2]. I had a WebProxy class where I had
an instance object that I had to pass to all kinds of other objects which just passed it on until it was finally useful. I replaced it now with
a simple (static) object and the code feels a lot better already. But now we loose configuration. So I was intrigued to see if I could use 
the reader monad to do all the configurations of the server. Do you have some pointers to some examples that flesh this out in more
concrete examples by now?


2) You mention the following code, and explain how A, B, C, D could be any kind of object,
like ints, or floats, or strings, or more complex objects. But those objects don't have either map or flatmap methods. I don't think
you explained how they got those methods. Did you import some scalaz implicit library?

def lift3ConfigReader[A, B, C, D](f: A => B => C => D):
  ConfigReader[A] =>
  ConfigReader[B] =>
  ConfigReader[C] =>
  ConfigReader[D] =
    a => b => c =>
      for{
        aa <- a
        bb <- b
        cc <- c
      } yield f(aa)(bb)(cc)


I think those were the two questions I had.

Henry


Jason Zaugg

unread,
Dec 6, 2011, 5:19:52 AM12/6/11
to scala...@googlegroups.com, tmo...@tmorris.net
ConfigReader has the flatMap/map methods, not the A/B/C.

Here's another example that shows how to use this pattern: https://gist.github.com/1395578

-jason

Tony Morris

unread,
Dec 6, 2011, 8:13:19 PM12/6/11
to scala...@googlegroups.com, bblfish
Hi mate.


On 12/06/2011 08:13 PM, bblfish wrote:
I Tony,

     thanks for this great intro to Reader Monads [1]  I went through the presentation, watched the video, and bought the mug. ;-) 
But I have a few questions remaining. 

1)  You start your talk by saying that one can solve the following problem

Let's pass the configuration to every function that requires it, including those for which it is simply passed on.
 
Indeed that is exactly the type of problem I had with Read-Write-Web project I am working on [2]. I had a WebProxy class where I had
an instance object that I had to pass to all kinds of other objects which just passed it on until it was finally useful. I replaced it now with
a simple (static) object and the code feels a lot better already. But now we loose configuration. So I was intrigued to see if I could use 
the reader monad to do all the configurations of the server. Do you have some pointers to some examples that flesh this out in more
concrete examples by now?

Yes, this sounds exactly like the problem that the reader monad would solve.

I don't have more examples and I could surely whip some up easily, but it's difficult to do this without knowing exactly what is going to help your understanding. Maybe I will answer the next question and that will help.




2) You mention the following code, and explain how A, B, C, D could be any kind of object,
like ints, or floats, or strings, or more complex objects. But those objects don't have either map or flatmap methods. I don't think
you explained how they got those methods. Did you import some scalaz implicit library?

def lift3ConfigReader[A, B, C, D](f: A => B => C => D):
  ConfigReader[A] =>
  ConfigReader[B] =>
  ConfigReader[C] =>
  ConfigReader[D] =
    a => b => c =>
      for{
        aa <- a
        bb <- b
        cc <- c
      } yield f(aa)(bb)(cc)

OK, so the ints and strings are not the data types on which map/flatMap are being called. However, I would like to point out that, besides some superficial syntax changes, the following two programs are equivalent if:
a) We run the for-comprehension in the identity monad.

case class Identity[A](a: A) {
    def map[B](f: A => B) = Identity(f(a))
    def flatMap[B](f: A => Identity[B]) = f(a)
}

b) We have a way of stepping in and out of Identity implicitly. That is, Id[X] and X are interchangeable.

Program 1:

val e1 = f(x)
val e2 = g(x, e1)
val e3 = h(e1)
val e4 = i(e3, e2)
j(e1, e4, e2)

Program 2:

for {
    e1 <- f(x)
    e2 <- g(x, e1)
    e3 <- h(e1)
    e4 <- i(e3, e2)
} yield j(e1, e4, e2)

So we see, we can do this to *any* program. However, for-comprehensions run on more than just Identity. They run on anything that has map/flatMap (etc.), such as this:

case class ConfigReader[A](f: Config => A) {
    def map[B](g: A => B) = ConfigReader(c => g(f(c)))
    def flatMap[B](g: A => ConfigReader[B]) = ConfigReader(c => g(f(c)).f(c))
}

This data type is just like any other with map/flatMap. The types are correct and it even obeys the monad laws.

So a program that was once using, say Int, then we transformed to say Identity[Int] (just for giggles, not because it was useful), we could then transform to ConfigReader[Int] and this time, we get the advantage that our values (Int, etc.) have access to an environment (Config), but we also have the advantage that we do not need to deal directly with the "passing of this environment" since the for-comprehension takes care of that for us -- after all, syntactically, they are much the same as a regular program. This makes the library code and the client code much less complex.

Other monads in this direction that have other types of uses are:
* State
case class State[S, A](f: S => (S, A))

* Writer
case class Writer[W, A](w: W, a: A) // flatMap requires a Monoid[W]

* ReaderWriterState (aka RWS)
case class RWS[R, W, S, A](f: R => S => (A, S, W))

* their transformer versions (I mention this only because in practice, they pop up regularly)
** case class StateT[S, F[_], A](f: S => F[(S, A)])
** case class WriterT[W, F[_], A](x: F[(W, A)])
** case class RWST[R, W, S, F[_], A](f: R => S => F[(A, S, W)])

HTH.




I think those were the two questions I had.

Henry




Henry Story

unread,
Dec 7, 2011, 1:27:04 PM12/7/11
to tmo...@tmorris.net, scala...@googlegroups.com

On 7 Dec 2011, at 02:13, Tony Morris wrote:

Hi mate.

Hi! :-)


On 12/06/2011 08:13 PM, bblfish wrote:
I Tony,

     thanks for this great intro to Reader Monads [1]  I went through the presentation, watched the video, and bought the mug. ;-) 
But I have a few questions remaining. 

1)  You start your talk by saying that one can solve the following problem

Let's pass the configuration to every function that requires it, including those for which it is simply passed on.
 
Indeed that is exactly the type of problem I had with Read-Write-Web project I am working on [2]. I had a WebProxy class where I had
an instance object that I had to pass to all kinds of other objects which just passed it on until it was finally useful. I replaced it now with
a simple (static) object and the code feels a lot better already. But now we loose configuration. So I was intrigued to see if I could use 
the reader monad to do all the configurations of the server. Do you have some pointers to some examples that flesh this out in more
concrete examples by now?

Yes, this sounds exactly like the problem that the reader monad would solve.

I don't have more examples and I could surely whip some up easily, but it's difficult to do this without knowing exactly what is going to help your understanding. Maybe I will answer the next question and that will help.

Yep, Socrates had this problem already as described by Plato where he is confronted with Meno's paradox, known as the learner's paradox
http://en.wikipedia.org/wiki/Meno : How can we find what we don't know, for if we don't know it, how will we recognise it, yet if we know it then
why are we looking? :-)
Thanks a lot, that clarifies things. It adds some background context. When I wrote the original e-mail this intriguing thought, which you just expressed so clearly, was floating in the back of my mind. 

But back to my configuration problem in the read-write-web, which I now need to look at from the point of view of Monads.

I have some objects that don't need to be Monads I think because they are singletons. That is I can access them easily from anywhere in my code without confusion. The Web for example is such a singleton - there is only one World Wide Web. So here I think I can just use one globally accessible object. This is useful because that means I can access it anywhere in my code with just a call to WWW.resource(url) for example, and so I don't have the issue of passing things around all the time. But what is a configuration other than a way of getting objects out of some state defined in some document? But then why not generalise a configuration object to the Web, since it is the space where we can find all information? 

Good so if we now think of a WWW object, which we can make requests on, what kind of objects are these going to return? Well very certainly not singletons. In the semantic web these return graphs (which are just a set of relations). So we can have a method like 

WWW.resource(u: URL) : Graph

So I am now thinking this Graph is close to the Configuration object we need. Perhaps if I rewrite your ConfigReader into a GraphMapper object it will help me put this in terms I am more familiar with.

case class GraphReader[A](f: Graph => A) {
    def map[B](g: A => B) = GraphReader(c => g(f(c)))
    def flatMap[B](g: A => GraphReader[B]) = GraphReader(c => g(f(c)).f(c))
}

so this function f that we have above is very similar to a SPARQL query. 
Say we have a graph and we want to extract the people in it then our function f could be
generated by something like

SELECT ?p ?name
WHERE {
    ?p a foaf:Person;
         foaf:name ?name .

which one could then use to create a simple set of  People, defined as
 case class Person(id: URI, name: String)

But what we would like to do is not extract those objects from the graph - as far as possible -  because there are objects that cannot really be extracted from graphs, such as blank nodes - these are existential quantifiers that exist inside a graph. I have the feeling that the general interest of Monads is that they are meant to allow us to continue working inside the context of the object, so that indeed they would be very useful in this case.

On the same topic I seem to have gathered that monads are meant to be  something encompassing the state of the World ( Monads are Elephants Part 4 ), which is nice because that is close to how the semantic web thinks of graphs. From the RDF Semantics spec section 1.3

The basic intuition of model-theoretic semantics is that asserting a sentence makes a claim about the 
world: it is another way of saying that the world is, in fact, so arranged as to be an interpretation which makes the sentence true. In other words, an assertion amounts to stating a constrainton the possible ways the world might be. Notice that there is no presumption here that any assertion contains enough information to specify a single unique interpretation. It is usually impossible to assert enough in any language to completely constrain the interpretations to a single possible world, so there is no such thing as 'the' unique interpretation of an RDF graph. In general, the larger an RDF graph is - the more it says about the world - then the smaller the set of interpretations that an assertion of the graph allows to be true - the fewer the ways the world could be, while making the asserted graph true of it.

Anyway I think there is something here where we could generalise the notion of configuration to any document with clearly defined semantics, so that your approach could be useable to extract information from any set of resources wherever they are. Then we have not only configuration sorted but a huge number of other issues.

I have the feeling that there is something here, and I am just wondering how I should go around getting it to work in the read-write-web project....

Henry


So a program that was once using, say Int, then we transformed to say Identity[Int] (just for giggles, not because it was useful), we could then transform to ConfigReader[Int] and this time, we get the advantage that our values (Int, etc.) have access to an environment (Config), but we also have the advantage that we do not need to deal directly with the "passing of this environment" since the for-comprehension takes care of that for us -- after all, syntactically, they are much the same as a regular program. This makes the library code and the client code much less complex.

Other monads in this direction that have other types of uses are:
* State
case class State[S, A](f: S => (S, A))

* Writer
case class Writer[W, A](w: W, a: A) // flatMap requires a Monoid[W]

* ReaderWriterState (aka RWS)
case class RWS[R, W, S, A](f: R => S => (A, S, W))

* their transformer versions (I mention this only because in practice, they pop up regularly)
** case class StateT[S, F[_], A](f: S => F[(S, A)])
** case class WriterT[W, F[_], A](x: F[(W, A)])
** case class RWST[R, W, S, F[_], A](f: R => S => F[(A, S, W)])

HTH.



I think those were the two questions I had.

Henry




-- 
Tony Morris
http://tmorris.net/


Social Web Architect
http://bblfish.net/

Alec Zorab

unread,
Dec 7, 2011, 1:43:40 PM12/7/11
to Henry Story, tmo...@tmorris.net, scala...@googlegroups.com
Henry,

I think you should take a look at some of Greg Meredith's stuff - he's
got a upcoming book (which I can't find a link to) and a number of
blog posts [1] and videos [2] about monads and the web :)

Hope some of this is of interest!

[1] http://biosimilarity.blogspot.com/
[2] http://channel9.msdn.com/Shows/Going+Deep/C9-Lectures-Greg-Meredith-Monadic-Design-Patterns-for-the-Web-Introduction-to-Monads

Raoul Duke

unread,
Dec 7, 2011, 4:36:20 PM12/7/11
to scala...@googlegroups.com
On Wed, Dec 7, 2011 at 10:27 AM, Henry Story <henry...@gmail.com> wrote:
> I have some objects that don't need to be Monads I think because they are
> singletons. That is I can access them easily from anywhere in my code
> without confusion. The Web for example is such a singleton - there is only
> one World Wide Web. So here I think I can just use one globally accessible

uhm, there are other reasons to avoid singletons.

testing often ends up requiring you to have more than one www.

sincerely.

Paul Butcher

unread,
Dec 7, 2011, 5:29:28 PM12/7/11
to Raoul Duke, scala...@googlegroups.com
On 7 Dec 2011, at 21:36, Raoul Duke wrote:
> uhm, there are other reasons to avoid singletons.
>
> testing often ends up requiring you to have more than one www.


This isn't a defence of singletons, but - if happen to find yourself having to write tests for code that uses them, you might be interested to know that ScalaMock can mock singletons...

http://scalamock.org/

:-)

--
paul.butcher->msgCount++

Snetterton, Castle Combe, Cadwell Park...
Who says I have a one track mind?

http://www.paulbutcher.com/
LinkedIn: http://www.linkedin.com/in/paulbutcher
MSN: pa...@paulbutcher.com
AIM: paulrabutcher
Skype: paulrabutcher

Henry Story

unread,
Dec 7, 2011, 7:00:03 PM12/7/11
to Jason Zaugg, scala...@googlegroups.com, tmo...@tmorris.net
Thanks, these are all helpful examples. Seeing those three options together like that is useful. 
At the same time it makes the Monad version look the most complicated out of the three, so presumably the
example domain here is too simple to show where the Monad version starts to shine.

I am trying to piece all this together, including how that fits into dependency injection as discussed

Henry



-jason


Patrick Roemer

unread,
Dec 8, 2011, 6:43:04 PM12/8/11
to scala...@googlegroups.com
Responding to Jason Zaugg:

> Here's another example that shows how to use this pattern:
> https://gist.github.com/1395578

Thanks for posting this comparison. I've asked a question about this
reader monad video example some time ago[1], and I still fail to
understand how this style is applied at a scale above method level -
perhaps you can enlighten me.

Just adding one more method invocation level to your example:

object Config0 {
def subFragment1(contextRoot: String) =
<a href={contextRoot + "/foo"}>foo</a>

def fragment1(contextRoot: String) =
<ul>{for(i <- (1 to 3))
yield <li>{subFragment1(contextRoot)}</li>}</ul>

def html(contextRoot: String) =
<html><body>{fragment1(contextRoot)}</body></html>

def render = html("/c1")
}

object Config1 {
val contextRoot =
new scala.util.DynamicVariable[String]("")

def subFragment1 =
<a href={contextRoot.value + "/foo"}>foo</a>

def fragment1 =
<ul>{for(i <- (1 to 3))
yield <li>{subFragment1}</li>}</ul>

def html = <html><body>{fragment1}</body></html>

def render = contextRoot.withValue("/c1") { html }
}

What would the idiomatic implementation for Config2 (the reader monad
variant) look like?

Best regards,
Patrick

[1] http://groups.google.com/group/scala-user/msg/a3ca9f967968ed09

Henry Story

unread,
Dec 11, 2011, 3:28:49 PM12/11/11
to scala-user, tmo...@tmorris.net
Following up on the mail below where I hinted that one could generalise the configuration problem to any  GRDDLable XML document out there [1] (and further in fact, including json using json-grddl for example) and use the Web as the configuration platform for one's objects, I tried to put a simple example together just to see how useful this could be.

I wrote this up in the read-write-web project in the WebID branch here:
(It is change set 149 in case you wish to get back to it if I end up removing it later)

So we have the very simple case class inspired from Tony Morris' talk

    45 case class GraphReader[A](extract: Resource => Validation[scala.Throwable,A]) {
    46   def map[B](g: A => B) = GraphReader(r => extract(r).map(g(_)))
    47   def flatMap[B](g: A => GraphReader[B]): GraphReader[B] = GraphReader(r => extract(r).map(g(_)).flatMap(_.extract(r)))
    48 }

Here we have a Resource that object that knows how to GET its graph from the web, and it turns it into a Validation object, in case there
are problems on the web. (Validation objects seem very similar to throwables to me, so it seems like Java throwables could somehow be mapped into these)

The in the Extractors object I defined a few of those methods form resources to Validation. Here for example is one that
finds all People that are defined in the graph (a person is defined in the graph if the URI of the person is the uri of the graph + "#something"
(mhh... I notice that this is not quite correctly implemented then...)

    96   def findDefinedPeople(m: Resource): Validation[scala.Throwable,Set[IdPerson]] = {
    97     for (gr<-m.get) yield {
    98       for (st <- gr.listStatements(null,RDF.`type`,FOAF.Person).asScala;
    99            val subj = st.getSubject;
   100            if (subj.isURIResource && subj.toString.startsWith(m.name.toString));
   101            st2 <- gr.listStatements(subj, FOAF.name,null).asScala
   102       ) yield {
   103         new IdPerson(subj)
   104       }
   105     }.toSet

The for example I can use that lower down in the main method to get an object

   132   val definedPeopleRd = new GraphReader[Set[IdPerson]](Extractors.findDefinedPeople)

   149     // extract the people who are defined in the graph (rarely more than one)
   150     for (people <- definedPeopleRd.extract(new URL(url));
   151          p <- people) {
   152       System.out.println("found "+p.name)
   153     }
   154     out.println

And we can even move from mappers defined an flat mapped extractor

   134   val definedPeopleFriends = definedPeopleRd.flatMap(people =>GraphReader[Set[IdPerson]]{
   135     resource: Resource =>
   136        resource.get.map(gr=>
   137          for ( p <- people;
   138                st <- gr.listStatements(p.webid, FOAF.knows, null).asScala ;
   139               val friend = st.getObject;
   140               if (friend.isURIResource)
   141          ) yield IdPerson(friend.asInstanceOf[JResource])
   142        )
   143   } )

So one should then easily be able to get the same result using map and staying at the scala object
layer.

Because essentially what is happening here is that we have two layers that have a one/one mapping

Layer A: Scala grapha of objects 
Layer B: RDF graph of relations

I tried for a while to clearly separate the two layers, but it's just too easy to tie them together by for example creating
objects that know their id in the graph.  That's what the 

    52 case class IdPerson(webid: JResource) {

class does. Essentially hidden in that Jena Resource (JResource) is a graph, that one uses to walk through the relations.
One could then create scala methods to map that. The difference between RDF and scala is that RDF is a lot more flexible, since you can
add any relation. ( RDF does Duck Typing right as I argued some time ago [2]. )

I wrote a mapper like this before in Java using byte code rewriting.

What I would like to know from the Scala functional crowd is what is the correct way to do this from the category theory perspective?
Perhaps there are some scalaz pieces that would make something very neat if assembled in the correct way? 

The map and flat map seem useful, though I think mostly people will want to stay either at the scala object level, or at the graph layer.
(though I really need to rebuild a scala graph layer as the Jena one is really quite ancient java and one can see its age quite clearly.

Look forward to some feedback. I am a functional programming newbie, and welcome some guidance :-)

Henry

[2] http://blogs.oracle.com/bblfish/entry/duck_typing_done_right
Reply all
Reply to author
Forward
0 new messages