- About Scala
- Documentation
- Code Examples
- Software
- Scala Developers
Re: Reader Monad [Video]
Tue, 2011-12-06, 11:13
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
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 thinkyou explained how they got those methods. Did you import some scalaz implicit library?
I think those were the two questions I had.
Henry
[1] presentation: http://dl.dropbox.com/u/7810909/docs/reader-monad/chunk-html/index.html video: http://vimeo.com/20674558[2] https://dvcs.w3.org/hg/read-write-web/
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 hadan 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 witha 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 moreconcrete 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 thinkyou 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
[1] presentation: http://dl.dropbox.com/u/7810909/docs/reader-monad/chunk-html/index.html video: http://vimeo.com/20674558[2] https://dvcs.w3.org/hg/read-write-web/
Wed, 2011-12-07, 02:51
#2
Re: Reader Monad [Video]
Hi mate.
On 12/06/2011 08:13 PM, bblfish wrote:
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.
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.
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
[1] presentation: http://dl.dropbox.com/u/7810909/docs/reader-monad/chunk-html/index.html video: http://vimeo.com/20674558 [2] https://dvcs.w3.org/hg/read-write-web/
-- Tony Morris http://tmorris.net/
Wed, 2011-12-07, 19:41
#3
Re: Reader Monad [Video]
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 paradoxhttp://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 thenwhy are we looking? :-)
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.
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 begenerated by something like
PREFIX foaf: <http://xmlns.com/foaf/0.1/>SELECT ?p ?nameWHERE { ?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
[1] presentation: http://dl.dropbox.com/u/7810909/docs/reader-monad/chunk-html/index.html video: http://vimeo.com/20674558 [2] https://dvcs.w3.org/hg/read-write-web/
-- Tony Morris http://tmorris.net/
Social Web Architect
http://bblfish.net/
Wed, 2011-12-07, 19:51
#4
Re: Re: Reader Monad [Video]
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-Mona...
On 7 December 2011 18:27, Henry Story wrote:
>
> 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? :-)
>
>
>
>
>
> 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.
>
>
> 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
>
> PREFIX foaf:
> 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
>
>
> [1] presentation:
> http://dl.dropbox.com/u/7810909/docs/reader-monad/chunk-html/index.html
> video: http://vimeo.com/20674558
> [2] https://dvcs.w3.org/hg/read-write-web/
>
>
>
> --
> Tony Morris
> http://tmorris.net/
>
>
> Social Web Architect
> http://bblfish.net/
>
Wed, 2011-12-07, 22:51
#5
Re: Re: Reader Monad [Video]
On Wed, Dec 7, 2011 at 10:27 AM, Henry Story 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.
Wed, 2011-12-07, 23:41
#6
Re: Reader Monad [Video]
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...
:-)
--
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: paul@paulbutcher.com
AIM: paulrabutcher
Skype: paulrabutcher
Thu, 2011-12-08, 01:01
#7
Re: Reader Monad [Video]
On 6 Dec 2011, at 11:19, Jason Zaugg wrote:
On Tue, Dec 6, 2011 at 11:13 AM, bblfish <henry.story@gmail.com> 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 problemLet'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 witha 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 moreconcrete 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 thinkyou 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.
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
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 theexample 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 discussedhttp://jboner.github.com/2008/10/06/real-world-scala-dependency-injection-di.html
Henry
-jason
Fri, 2011-12-09, 00:51
#8
Re: Reader Monad [Video]
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) =
foo
def fragment1(contextRoot: String) =
- {for(i <- (1 to 3))
- {subFragment1(contextRoot)}
yield
}
def html(contextRoot: String) =
{fragment1(contextRoot)}
def render = html("/c1")
}
object Config1 {
val contextRoot =
new scala.util.DynamicVariable[String]("")
def subFragment1 =
foo
def fragment1 =
- {for(i <- (1 to 3))
- {subFragment1}
yield
}
def html = {fragment1}
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
Sun, 2011-12-11, 21:31
#9
Re: Reader Monad [Video] and Semantic Web
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: https://dvcs.w3.org/hg/read-write-web/file/893ac9c9c019/src/main/scala/sommer/GraphReader.scala(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
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 thereare 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 thatfinds 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...)
The for example I can use that lower down in the main method to get an object
And we can even move from mappers defined an flat mapped extractor
So one should then easily be able to get the same result using map and staying at the scala objectlayer.
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 creatingobjects that know their id in the graph. That's what the
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 canadd 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
[1] http://www.w3.org/TR/grddl/[2] http://blogs.oracle.com/bblfish/entry/duck_typing_done_right
On 7 Dec 2011, at 19:27, Henry Story wrote:
Social Web Architect
http://bblfish.net/
I wrote this up in the read-write-web project in the WebID branch here: https://dvcs.w3.org/hg/read-write-web/file/893ac9c9c019/src/main/scala/sommer/GraphReader.scala(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
44
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 thereare 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 thatfinds 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
106 }
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 objectlayer.
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 creatingobjects 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 canadd 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
[1] http://www.w3.org/TR/grddl/[2] http://blogs.oracle.com/bblfish/entry/duck_typing_done_right
On 7 Dec 2011, at 19:27, Henry Story wrote:
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 paradoxhttp://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 thenwhy are we looking? :-)
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.
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 begenerated by something like
PREFIX foaf: <http://xmlns.com/foaf/0.1/>SELECT ?p ?nameWHERE { ?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.3The 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
[1] presentation: http://dl.dropbox.com/u/7810909/docs/reader-monad/chunk-html/index.html video: http://vimeo.com/20674558 [2] https://dvcs.w3.org/hg/read-write-web/
-- Tony Morris http://tmorris.net/
Social Web Architect
http://bblfish.net/
Social Web Architect
http://bblfish.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