- About Scala
- Documentation
- Code Examples
- Software
- Scala Developers
i think i got it (monads and stuff)
Sun, 2011-07-24, 13:48
after reading lots of stuff on monads, i made up my own explanation that
is incredibly simple and doesn't contain cryptic symbols :)
it goes like this:
class Wrapper(x:X)
that is a monad. i left out the confusing parts
you use it like this:
instead of
val myMutableThing = ...
myMutableThing.mutate()
you do
val monad = new Wrapper(myImmutableThing)
val nextMonad = monad.chainOperation(mutation)
and later:
lastMonad.result
does that make sense so far? not really? well, it opens a whole new
world. the monad is a "void-monad" so far, it doesn't do anything. what
makes it cool is that you can make it "carry something along"
instead of a changing state, you have a chain of things that describe
the changes that accumulate along the way.
like the loggingmonad here:
http://www.lambdascale.com/2010/12/the-adventures-of-a-java-developer-in...
Sun, 2011-07-24, 22:17
#2
Re: i think i got it (monads and stuff)
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
On 24/07/11 22:48, HamsterofDeath wrote:
> after reading lots of stuff on monads, i made up my own explanation
> that is incredibly simple and doesn't contain cryptic symbols :)
>
> it goes like this: class Wrapper(x:X)
>
> that is a monad. i left out the confusing parts
>
> you use it like this:
>
> instead of
>
> val myMutableThing = ... myMutableThing.mutate()
>
> you do
>
> val monad = new Wrapper(myImmutableThing) val nextMonad =
> monad.chainOperation(mutation)
>
> and later: lastMonad.result
>
> does that make sense so far? not really? well, it opens a whole
> new world. the monad is a "void-monad" so far, it doesn't do
> anything. what makes it cool is that you can make it "carry
> something along" instead of a changing state, you have a chain of
> things that describe the changes that accumulate along the way.
> like the loggingmonad here:
> http://www.lambdascale.com/2010/12/the-adventures-of-a-java-developer-in...
>
>
This
>
looks like the identity monad.
You should be able to now fill this out:
trait Monad[F[_]] {
def point[A](a: => A): F[A]
def bind[A, B](f: A => F[B]): F[A] => F[B]
}
case class Identity[A](a: A)
object Monad {
val IdentityMonad: Monad[Identity] = error("todo")
}
You may be hinting at the state monad:
case class State[S, A](k: S => (A, S))
def StateMonad[S]: Monad[({type ?[?] = State[S, ?]})#?] = error("todo")
The whole "point" of monads is that they give rise to an enormously
useful library. Everything else is incidental.
The "logging" monad (transformer) is covered here:
http://stackoverflow.com/questions/2322783/how-to-add-tracing-within-a-f...
Mon, 2011-07-25, 18:27
#3
Re: i think i got it (monads and stuff)
Dear HoD,
What Kris said. Also, notice that the requirements are stratified:
Best wishes,
--greg
On Sun, Jul 24, 2011 at 1:33 PM, Kris Nuttycombe <kris.nuttycombe@gmail.com> wrote:
--
L.G. Meredith
Managing Partner
Biosimilarity LLC
7329 39th Ave SWSeattle, WA 98136
+1 206.650.3740
http://biosimilarity.blogspot.com
What Kris said. Also, notice that the requirements are stratified:
- You need functoriality of the type constructor (Wrapper)
- You need naturality of unit (putting stuff into Wrapper) and mult (flattening nested Wrappers)
- You need coherent interaction amongst unit and mult (this is the bit that is usually referred to as the monad laws)
Best wishes,
--greg
On Sun, Jul 24, 2011 at 1:33 PM, Kris Nuttycombe <kris.nuttycombe@gmail.com> wrote:
This is a good start! Monads are quite frequently (but not always)
about sequencing operations. One thing I'd encourage though is that
you not ignore the monad laws - with your newfound understanding, they
should be easy to remember.
A really good exercise to deepen your understanding is to implement
the Reader monad. Here's a skeleton that you can fill in the
implementation for, if you like: https://gist.github.com/1037030
On Sun, Jul 24, 2011 at 6:48 AM, HamsterofDeath <h-star@gmx.de> wrote:
> after reading lots of stuff on monads, i made up my own explanation that
> is incredibly simple and doesn't contain cryptic symbols :)
>
> it goes like this:
> class Wrapper(x:X)
>
> that is a monad. i left out the confusing parts
>
> you use it like this:
>
> instead of
>
> val myMutableThing = ...
> myMutableThing.mutate()
>
> you do
>
> val monad = new Wrapper(myImmutableThing)
> val nextMonad = monad.chainOperation(mutation)
>
> and later:
> lastMonad.result
>
> does that make sense so far? not really? well, it opens a whole new
> world. the monad is a "void-monad" so far, it doesn't do anything. what
> makes it cool is that you can make it "carry something along"
> instead of a changing state, you have a chain of things that describe
> the changes that accumulate along the way.
> like the loggingmonad here:
> http://www.lambdascale.com/2010/12/the-adventures-of-a-java-developer-in-monadland/
>
>
>
--
L.G. Meredith
Managing Partner
Biosimilarity LLC
7329 39th Ave SWSeattle, WA 98136
+1 206.650.3740
http://biosimilarity.blogspot.com
Mon, 2011-07-25, 19:07
#4
Re: i think i got it (monads and stuff)
this compiles:
trait Monad[F[_]] {
def point[A](a: => A): F[A]
def bind[A, B](f: A => F[B]): F[A] => F[B]
}
case class Identity[A](a: A)
object Monad {
val IdentityMonad: Monad[Identity] = new Monad[Identity] {
def bind[A, B](f: (A) => Identity[B]) = (e:Identity[A]) => f(e.a)
def point[A](a: => A) = Identity(a)
}
}
val identity = Monad.IdentityMonad.point("hi")
val transformer = Monad.IdentityMonad.bind((e: String) => Monad.IdentityMonad.point(e.toInt))
val wohoo = transformer.apply(identity)
Am 24.07.2011 23:10, schrieb Tony Morris:
> trait Monad[F[_]] {
> def point[A](a: => A): F[A]
> def bind[A, B](f: A => F[B]): F[A] => F[B]
> }
>
> case class Identity[A](a: A)
>
> object Monad {
> val IdentityMonad: Monad[Identity] = error("todo")
> }
trait Monad[F[_]] {
def point[A](a: => A): F[A]
def bind[A, B](f: A => F[B]): F[A] => F[B]
}
case class Identity[A](a: A)
object Monad {
val IdentityMonad: Monad[Identity] = new Monad[Identity] {
def bind[A, B](f: (A) => Identity[B]) = (e:Identity[A]) => f(e.a)
def point[A](a: => A) = Identity(a)
}
}
val identity = Monad.IdentityMonad.point("hi")
val transformer = Monad.IdentityMonad.bind((e: String) => Monad.IdentityMonad.point(e.toInt))
val wohoo = transformer.apply(identity)
Am 24.07.2011 23:10, schrieb Tony Morris:
> trait Monad[F[_]] {
> def point[A](a: => A): F[A]
> def bind[A, B](f: A => F[B]): F[A] => F[B]
> }
>
> case class Identity[A](a: A)
>
> object Monad {
> val IdentityMonad: Monad[Identity] = error("todo")
> }
Mon, 2011-07-25, 20:07
#5
Re: i think i got it (monads and stuff)
this might be a reader monad
class Reader[I] extends Monad2[({type M[O] = (I) => O})#M] {
def pure[A](a: A): (I) => A = (in:I) => a
def bind[A, B](m: (I) => A, f: A => ((I) => B)): (I) => B = (i:I) => f(m(i))(i)
}
it might help if i knew what it's supposed to do. this one just spits out functions that convert any I into and B and it ignores the input parameter at the "pure"-method which does not seem to make much sense.
Am 25.07.2011 20:05, schrieb HamsterofDeath:
class Reader[I] extends Monad2[({type M[O] = (I) => O})#M] {
def pure[A](a: A): (I) => A = (in:I) => a
def bind[A, B](m: (I) => A, f: A => ((I) => B)): (I) => B = (i:I) => f(m(i))(i)
}
it might help if i knew what it's supposed to do. this one just spits out functions that convert any I into and B and it ignores the input parameter at the "pure"-method which does not seem to make much sense.
Am 25.07.2011 20:05, schrieb HamsterofDeath:
4E2DB087 [dot] 1000805 [at] gmx [dot] de" type="cite"> this compiles:
trait Monad[F[_]] {
def point[A](a: => A): F[A]
def bind[A, B](f: A => F[B]): F[A] => F[B]
}
case class Identity[A](a: A)
object Monad {
val IdentityMonad: Monad[Identity] = new Monad[Identity] {
def bind[A, B](f: (A) => Identity[B]) = (e:Identity[A]) => f(e.a)
def point[A](a: => A) = Identity(a)
}
}
val identity = Monad.IdentityMonad.point("hi")
val transformer = Monad.IdentityMonad.bind((e: String) => Monad.IdentityMonad.point(e.toInt))
val wohoo = transformer.apply(identity)
Am 24.07.2011 23:10, schrieb Tony Morris:
> trait Monad[F[_]] {
> def point[A](a: => A): F[A]
> def bind[A, B](f: A => F[B]): F[A] => F[B]
> }
>
> case class Identity[A](a: A)
>
> object Monad {
> val IdentityMonad: Monad[Identity] = error("todo")
> }
Mon, 2011-07-25, 20:37
#6
Re: i think i got it (monads and stuff)
this doesn't make sense. i can't chain the bind-calls.
using option and any collection, i can do this:
a.map(_.toString).map(_toInt) and so on
using dumb functions i can do
a andThen b andThen c
how can i do this with the reader monad?
Am 25.07.2011 21:05, schrieb HamsterofDeath:
using option and any collection, i can do this:
a.map(_.toString).map(_toInt) and so on
using dumb functions i can do
a andThen b andThen c
how can i do this with the reader monad?
Am 25.07.2011 21:05, schrieb HamsterofDeath:
4E2DBE69 [dot] 7040702 [at] gmx [dot] de" type="cite"> this might be a reader monad
class Reader[I] extends Monad2[({type M[O] = (I) => O})#M] {
def pure[A](a: A): (I) => A = (in:I) => a
def bind[A, B](m: (I) => A, f: A => ((I) => B)): (I) => B = (i:I) => f(m(i))(i)
}
it might help if i knew what it's supposed to do. this one just spits out functions that convert any I into and B and it ignores the input parameter at the "pure"-method which does not seem to make much sense.
Am 25.07.2011 20:05, schrieb HamsterofDeath:4E2DB087 [dot] 1000805 [at] gmx [dot] de" type="cite"> this compiles:
trait Monad[F[_]] {
def point[A](a: => A): F[A]
def bind[A, B](f: A => F[B]): F[A] => F[B]
}
case class Identity[A](a: A)
object Monad {
val IdentityMonad: Monad[Identity] = new Monad[Identity] {
def bind[A, B](f: (A) => Identity[B]) = (e:Identity[A]) => f(e.a)
def point[A](a: => A) = Identity(a)
}
}
val identity = Monad.IdentityMonad.point("hi")
val transformer = Monad.IdentityMonad.bind((e: String) => Monad.IdentityMonad.point(e.toInt))
val wohoo = transformer.apply(identity)
Am 24.07.2011 23:10, schrieb Tony Morris:
> trait Monad[F[_]] {
> def point[A](a: => A): F[A]
> def bind[A, B](f: A => F[B]): F[A] => F[B]
> }
>
> case class Identity[A](a: A)
>
> object Monad {
> val IdentityMonad: Monad[Identity] = error("todo")
> }
Mon, 2011-07-25, 21:47
#7
Re: i think i got it (monads and stuff)
I'd like to know other opinions, but I find that avoiding OO makes it easier to reason about these abstract concepts in Scala. Here is my version of the identity monad:
trait Monad[M[_]] {
def bind[A, B](ma:M[A])(f:A => M[B]):M[B]
def unit[A](a:A):M[A]
def fmap[A, B](f:A => B):M[A] => M[B]
def ap[A, B](f:M[A => B]):M[A] => M[B]
}
type Id[A] = A
implicit val mId = new Monad[Id] {
def bind[A, B](a:Id[A])(f:A => Id[B]) = f(a)
def unit[A](a:A) = a
def fmap[A, B](f:A => B) = f
def ap[A, B](f:Id[A => B]) = f
}
(See how identity fmap a function to itself.)
Now you can box the monad inside an object to use it in a for-comprehension but this is incidental (I'm wondering if the boxing is optimized away by the JVM).
trait MonadTrait[M[_], A] {
def flatMap[B](f:A => M[B]):M[B]
def map[B](f:A => B):M[B]
}
implicit def idBox[A](ma:Id[A])(implicit m:Monad[Id]) = new MonadTrait[Id, A] {
def flatMap[B](f:A => Id[B]) = m.bind(ma)(f)
def map[B](f:A => B):Id[B] = m.fmap(f)(ma)
}
def test(x:Id[Int]) = for {
y <- x * x
z <- y + y
} yield (y + z)
println(test(42))
Have fun!
2011/7/25 HamsterofDeath <h-star@gmx.de>
--
Sébastien
trait Monad[M[_]] {
def bind[A, B](ma:M[A])(f:A => M[B]):M[B]
def unit[A](a:A):M[A]
def fmap[A, B](f:A => B):M[A] => M[B]
def ap[A, B](f:M[A => B]):M[A] => M[B]
}
type Id[A] = A
implicit val mId = new Monad[Id] {
def bind[A, B](a:Id[A])(f:A => Id[B]) = f(a)
def unit[A](a:A) = a
def fmap[A, B](f:A => B) = f
def ap[A, B](f:Id[A => B]) = f
}
(See how identity fmap a function to itself.)
Now you can box the monad inside an object to use it in a for-comprehension but this is incidental (I'm wondering if the boxing is optimized away by the JVM).
trait MonadTrait[M[_], A] {
def flatMap[B](f:A => M[B]):M[B]
def map[B](f:A => B):M[B]
}
implicit def idBox[A](ma:Id[A])(implicit m:Monad[Id]) = new MonadTrait[Id, A] {
def flatMap[B](f:A => Id[B]) = m.bind(ma)(f)
def map[B](f:A => B):Id[B] = m.fmap(f)(ma)
}
def test(x:Id[Int]) = for {
y <- x * x
z <- y + y
} yield (y + z)
println(test(42))
Have fun!
2011/7/25 HamsterofDeath <h-star@gmx.de>
this compiles:
trait Monad[F[_]] {
def point[A](a: => A): F[A]
def bind[A, B](f: A => F[B]): F[A] => F[B]
}
case class Identity[A](a: A)
object Monad {
val IdentityMonad: Monad[Identity] = new Monad[Identity] {
def bind[A, B](f: (A) => Identity[B]) = (e:Identity[A]) => f(e.a)
def point[A](a: => A) = Identity(a)
}
}
val identity = Monad.IdentityMonad.point("hi")
val transformer = Monad.IdentityMonad.bind((e: String) => Monad.IdentityMonad.point(e.toInt))
val wohoo = transformer.apply(identity)
Am 24.07.2011 23:10, schrieb Tony Morris:
> trait Monad[F[_]] {
> def point[A](a: => A): F[A]
> def bind[A, B](f: A => F[B]): F[A] => F[B]
> }
>
> case class Identity[A](a: A)
>
> object Monad {
> val IdentityMonad: Monad[Identity] = error("todo")
> }
--
Sébastien
Mon, 2011-07-25, 21:57
#8
Re: i think i got it (monads and stuff)
I mean this is implementation specific.
2011/7/25 Sébastien Bocq <sebastien.bocq@gmail.com>
--
Sébastien
2011/7/25 Sébastien Bocq <sebastien.bocq@gmail.com>
I'd like to know other opinions, but I find that avoiding OO makes it easier to reason about these abstract concepts in Scala. Here is my version of the identity monad:
trait Monad[M[_]] {
def bind[A, B](ma:M[A])(f:A => M[B]):M[B]
def unit[A](a:A):M[A]
def fmap[A, B](f:A => B):M[A] => M[B]
def ap[A, B](f:M[A => B]):M[A] => M[B]
}
type Id[A] = A
implicit val mId = new Monad[Id] {
def bind[A, B](a:Id[A])(f:A => Id[B]) = f(a)
def unit[A](a:A) = a
def fmap[A, B](f:A => B) = f
def ap[A, B](f:Id[A => B]) = f
}
(See how identity fmap a function to itself.)
Now you can box the monad inside an object to use it in a for-comprehension but this is incidental (I'm wondering if the boxing is optimized away by the JVM).
trait MonadTrait[M[_], A] {
def flatMap[B](f:A => M[B]):M[B]
def map[B](f:A => B):M[B]
}
implicit def idBox[A](ma:Id[A])(implicit m:Monad[Id]) = new MonadTrait[Id, A] {
def flatMap[B](f:A => Id[B]) = m.bind(ma)(f)
def map[B](f:A => B):Id[B] = m.fmap(f)(ma)
}
def test(x:Id[Int]) = for {
y <- x * x
z <- y + y
} yield (y + z)
println(test(42))
Have fun!
2011/7/25 HamsterofDeath <h-star@gmx.de>this compiles:
trait Monad[F[_]] {
def point[A](a: => A): F[A]
def bind[A, B](f: A => F[B]): F[A] => F[B]
}
case class Identity[A](a: A)
object Monad {
val IdentityMonad: Monad[Identity] = new Monad[Identity] {
def bind[A, B](f: (A) => Identity[B]) = (e:Identity[A]) => f(e.a)
def point[A](a: => A) = Identity(a)
}
}
val identity = Monad.IdentityMonad.point("hi")
val transformer = Monad.IdentityMonad.bind((e: String) => Monad.IdentityMonad.point(e.toInt))
val wohoo = transformer.apply(identity)
Am 24.07.2011 23:10, schrieb Tony Morris:
> trait Monad[F[_]] {
> def point[A](a: => A): F[A]
> def bind[A, B](f: A => F[B]): F[A] => F[B]
> }
>
> case class Identity[A](a: A)
>
> object Monad {
> val IdentityMonad: Monad[Identity] = error("todo")
> }
--
Sébastien
--
Sébastien
Mon, 2011-07-25, 22:47
#9
Re: i think i got it (monads and stuff)
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Yes this is often called the reader monad. It does pretty much what
its body does. The important point is that now you pick up the entire
monad library for all values of the type [I]Function1[I, _].
Here is a talk about the reader monad
http://blog.tmorris.net/configuration-without-the-bugs-and-gymnastics/
On 26/07/11 05:05, HamsterofDeath wrote:
> this might be a reader monad
>
> class Reader[I] extends Monad2[({type M[O] = (I) => O})#M] { def
> pure[A](a: A): (I) => A = (in:I) => a
>
> def bind[A, B](m: (I) => A, f: A => ((I) => B)): (I) => B = (i:I)
> => f(m(i))(i) }
>
> it might help if i knew what it's supposed to do. this one just
> spits out functions that convert any I into and B and it ignores
> the input parameter at the "pure"-method which does not seem to
> make much sense.
>
> Am 25.07.2011 20:05, schrieb HamsterofDeath:
>> this compiles: trait Monad[F[_]] { def point[A](a: => A): F[A]
>>
>> def bind[A, B](f: A => F[B]): F[A] => F[B] }
>>
>> case class Identity[A](a: A)
>>
>> object Monad { val IdentityMonad: Monad[Identity] = new
>> Monad[Identity] { def bind[A, B](f: (A) => Identity[B]) =
>> (e:Identity[A]) => f(e.a)
>>
>> def point[A](a: => A) = Identity(a) } }
>>
>> val identity = Monad.IdentityMonad.point("hi") val transformer =
>> Monad.IdentityMonad.bind((e: String) =>
>> Monad.IdentityMonad.point(e.toInt)) val wohoo =
>> transformer.apply(identity)
>>
>>
>> Am 24.07.2011 23:10, schrieb Tony Morris:
>>> trait Monad[F[_]] { def point[A](a: => A): F[A] def bind[A,
>>> B](f: A => F[B]): F[A] => F[B] }
>>>
>>> case class Identity[A](a: A)
>>>
>>> object Monad { val IdentityMonad: Monad[Identity] =
>>> error("todo") }
>>
>>
>
>
Mon, 2011-07-25, 22:57
#10
Re: i think i got it (monads and stuff)
the longer i look at this
trait Monad[M[_]] {
def bind[A, B](ma:M[A])(f:A => M[B]):M[B]
def unit[A](a:A):M[A]
def fmap[A, B](f:A => B):M[A] => M[B]
def ap[A, B](f:M[A => B]):M[A] => M[B]
}
the less sense it makes.
i understand wrapping a:A in m:M[A].
i understand mapping M[A] to M[B]
simple.
i understand if you say "monad = both methods together", making a monad a utiliy object, not different from the well known *Utils-classes of java.
i understand how option works.
but i cannot make the mental jump to the monad trait. the implementation is nothing more than a function composer which i simply could do directly or via not-part-of-a-trait utility-methods if the logic is more complex.
my brain refuses to see any sense in an implementation of a monad trait that does not return an instance of monad in the bind and unit method and accepts an instance of monad in the bind method.
Am 25.07.2011 22:37, schrieb Sébastien Bocq:
trait Monad[M[_]] {
def bind[A, B](ma:M[A])(f:A => M[B]):M[B]
def unit[A](a:A):M[A]
def fmap[A, B](f:A => B):M[A] => M[B]
def ap[A, B](f:M[A => B]):M[A] => M[B]
}
the less sense it makes.
i understand wrapping a:A in m:M[A].
i understand mapping M[A] to M[B]
simple.
i understand if you say "monad = both methods together", making a monad a utiliy object, not different from the well known *Utils-classes of java.
i understand how option works.
but i cannot make the mental jump to the monad trait. the implementation is nothing more than a function composer which i simply could do directly or via not-part-of-a-trait utility-methods if the logic is more complex.
my brain refuses to see any sense in an implementation of a monad trait that does not return an instance of monad in the bind and unit method and accepts an instance of monad in the bind method.
Am 25.07.2011 22:37, schrieb Sébastien Bocq:
CAFJkGuG0adK01GO3Su7s_nKASM_MxpFf3HsO9E5vHoHDgGHTUg [at] mail [dot] gmail [dot] com" type="cite">I mean this is implementation specific.
2011/7/25 Sébastien Bocq <sebastien [dot] bocq [at] gmail [dot] com" rel="nofollow">sebastien.bocq@gmail.com>
I'd like to know other opinions, but I find that avoiding OO makes it easier to reason about these abstract concepts in Scala. Here is my version of the identity monad:
trait Monad[M[_]] {
def bind[A, B](ma:M[A])(f:A => M[B]):M[B]
def unit[A](a:A):M[A]
def fmap[A, B](f:A => B):M[A] => M[B]
def ap[A, B](f:M[A => B]):M[A] => M[B]
}
type Id[A] = A
implicit val mId = new Monad[Id] {
def bind[A, B](a:Id[A])(f:A => Id[B]) = f(a)
def unit[A](a:A) = a
def fmap[A, B](f:A => B) = f
def ap[A, B](f:Id[A => B]) = f
}
(See how identity fmap a function to itself.)
Now you can box the monad inside an object to use it in a for-comprehension but this is incidental (I'm wondering if the boxing is optimized away by the JVM).
trait MonadTrait[M[_], A] {
def flatMap[B](f:A => M[B]):M[B]
def map[B](f:A => B):M[B]
}
implicit def idBox[A](ma:Id[A])(implicit m:Monad[Id]) = new MonadTrait[Id, A] {
def flatMap[B](f:A => Id[B]) = m.bind(ma)(f)
def map[B](f:A => B):Id[B] = m.fmap(f)(ma)
}
def test(x:Id[Int]) = for {
y <- x * x
z <- y + y
} yield (y + z)
println(test(42))
Have fun!
2011/7/25 HamsterofDeath <h-star [at] gmx [dot] de" target="_blank" rel="nofollow">h-star@gmx.de>
this compiles:
trait Monad[F[_]] {
def point[A](a: => A): F[A]
def bind[A, B](f: A => F[B]): F[A] => F[B]
}
case class Identity[A](a: A)
object Monad {
val IdentityMonad: Monad[Identity] = new Monad[Identity] {
def bind[A, B](f: (A) => Identity[B]) = (e:Identity[A]) => f(e.a)
def point[A](a: => A) = Identity(a)
}
}
val identity = Monad.IdentityMonad.point("hi")
val transformer = Monad.IdentityMonad.bind((e: String) => Monad.IdentityMonad.point(e.toInt))
val wohoo = transformer.apply(identity)
Am 24.07.2011 23:10, schrieb Tony Morris:
> trait Monad[F[_]] {
> def point[A](a: => A): F[A]
> def bind[A, B](f: A => F[B]): F[A] => F[B]
> }
>
> case class Identity[A](a: A)
>
> object Monad {
> val IdentityMonad: Monad[Identity] = error("todo")
> }
--
Sébastien
--
Sébastien
Mon, 2011-07-25, 22:57
#11
RE: i think i got it (monads and stuff)
He he – welcome to the world of mathematical abstractions J and types
What you call a monad is just a concept. What scala likes a monad to be is an object of type F[A] which implements this method:
def flatmap[B](f: A => F[B]): F[B]
where flatmap corresponds to Tony’s bind() and the class’s type constructor is the point().
You can see that Tony’s Monad trait below is not a proper scala monad, meaning it is not recognized in for comprehensions as being a monad. It is very useful however to decouple the scala syntax from the underlying concept.
In fact, in the trait below, the bind simply returns a function which does the binding… not the result.
Using the monad definition you started with, you need to make it scala friendly… I did not try to compile the code below but you should get the idea:
// scala friendly monad
trait ScalaMonad[F[_]] {
def flatmap[A, B](f: A => F[B]): F[B] // checkout the return value compared to the bind()
def map[A, B](f: A => B): F[B]
}
class ScalaMonadAdapter[F[_], M <: Monad[F]] (val container:F, val m:M) implements ScalaMonad {
def flatmap[A, B](f: A => F[B]): F[A] => F[B] = m.bind(f) (container)
def map[A, B](f: A => B): F[A] => F[B] = flatmap (point(f(_))) (container)
}
This pattern is used in scalaz to separate the actual monadic implementation from the underlying container or type. Another way to do it is to have your container derive the ScalaMonad trait
Dang, almost missed my train – have fun
RAzie
From: scala-user@googlegroups.com [mailto:scala-user@googlegroups.com] On Behalf Of HamsterofDeath
Sent: July-25-11 3:28 PM
To: scala-user@googlegroups.com
Subject: Re: [scala-user] i think i got it (monads and stuff)
this doesn't make sense. i can't chain the bind-calls.
using option and any collection, i can do this:
a.map(_.toString).map(_toInt) and so on
using dumb functions i can do
a andThen b andThen c
how can i do this with the reader monad?
Am 25.07.2011 21:05, schrieb HamsterofDeath:
this might be a reader monad
class Reader[I] extends Monad2[({type M[O] = (I) => O})#M] {
def pure[A](a: A): (I) => A = (in:I) => a
def bind[A, B](m: (I) => A, f: A => ((I) => B)): (I) => B = (i:I) => f(m(i))(i)
}
it might help if i knew what it's supposed to do. this one just spits out functions that convert any I into and B and it ignores the input parameter at the "pure"-method which does not seem to make much sense.
Am 25.07.2011 20:05, schrieb HamsterofDeath:
this compiles:
trait Monad[F[_]] {
def point[A](a: => A): F[A]
def bind[A, B](f: A => F[B]): F[A] => F[B]
}
case class Identity[A](a: A)
object Monad {
val IdentityMonad: Monad[Identity] = new Monad[Identity] {
def bind[A, B](f: (A) => Identity[B]) = (e:Identity[A]) => f(e.a)
def point[A](a: => A) = Identity(a)
}
}
val identity = Monad.IdentityMonad.point("hi")
val transformer = Monad.IdentityMonad.bind((e: String) => Monad.IdentityMonad.point(e.toInt))
val wohoo = transformer.apply(identity)
Am 24.07.2011 23:10, schrieb Tony Morris:
> trait Monad[F[_]] {
> def point[A](a: => A): F[A]
> def bind[A, B](f: A => F[B]): F[A] => F[B]
> }
>
> case class Identity[A](a: A)
>
> object Monad {
> val IdentityMonad: Monad[Identity] = error("todo")
> }
Mon, 2011-07-25, 23:37
#12
Re: i think i got it (monads and stuff)
andThen == fmap
with bind, each application "reads" from the argument passed to the
invocation of the composed function as well as the result from the
previous application in the chain.
On Mon, Jul 25, 2011 at 1:27 PM, HamsterofDeath wrote:
> this doesn't make sense. i can't chain the bind-calls.
> using option and any collection, i can do this:
> a.map(_.toString).map(_toInt) and so on
>
> using dumb functions i can do
> a andThen b andThen c
>
> how can i do this with the reader monad?
>
> Am 25.07.2011 21:05, schrieb HamsterofDeath:
>
> this might be a reader monad
>
> class Reader[I] extends Monad2[({type M[O] = (I) => O})#M] {
> def pure[A](a: A): (I) => A = (in:I) => a
>
> def bind[A, B](m: (I) => A, f: A => ((I) => B)): (I) => B = (i:I) =>
> f(m(i))(i)
> }
>
> it might help if i knew what it's supposed to do. this one just spits out
> functions that convert any I into and B and it ignores the input parameter
> at the "pure"-method which does not seem to make much sense.
>
> Am 25.07.2011 20:05, schrieb HamsterofDeath:
>
> this compiles:
> trait Monad[F[_]] {
> def point[A](a: => A): F[A]
>
> def bind[A, B](f: A => F[B]): F[A] => F[B]
> }
>
> case class Identity[A](a: A)
>
> object Monad {
> val IdentityMonad: Monad[Identity] = new Monad[Identity] {
> def bind[A, B](f: (A) => Identity[B]) = (e:Identity[A]) => f(e.a)
>
> def point[A](a: => A) = Identity(a)
> }
> }
>
> val identity = Monad.IdentityMonad.point("hi")
> val transformer = Monad.IdentityMonad.bind((e: String) =>
> Monad.IdentityMonad.point(e.toInt))
> val wohoo = transformer.apply(identity)
>
>
> Am 24.07.2011 23:10, schrieb Tony Morris:
>> trait Monad[F[_]] {
>> def point[A](a: => A): F[A]
>> def bind[A, B](f: A => F[B]): F[A] => F[B]
>> }
>>
>> case class Identity[A](a: A)
>>
>> object Monad {
>> val IdentityMonad: Monad[Identity] = error("todo")
>> }
>
>
>
>
>
Mon, 2011-07-25, 23:47
#13
RE: i think i got it (monads and stuff)
He he – safely in the train I can review my copy/pastes. Interestingly enough, Outlook does SEND instead of SAVE if I use ALT+s instead of CTRL+s. Must be the CTRL Monad J Sorry for the contraption I sent previously.
Here’s code that actually compiles:
trait Monad[F[_]] {
def point[A](a: => A): F[A]
def bind[A, B](f: A => F[B]): F[A] => F[B]
}
trait ScalaMonad[A] {
def flatmap[B](f: A => ScalaMonad[B]): ScalaMonad[B] // checkout the return value compared to the bind()
def map[B](f: A => B): ScalaMonad[B]
}
class ScalaMonadAdapter [A, F[_], M <: Monad[F]] (val container:F[A], val m:M) extends ScalaMonad[A] {
def flatmap[B](f: A => ScalaMonad[B]): ScalaMonad[B] =
new ScalaMonadAdapter[B,F,M] (m.bind({a:A => f(a).asInstanceOf[ScalaMonadAdapter[B, F, M]].container}) (container), m)
def map[B](f: A => B): ScalaMonad[B] = error ("todo")
}
Now you can see how you can chain maps or flatmaps on objects that implement ScalaMonad…
Note the complications when using a base trait – this is why it’s not done that way in the scala library, most likely.
From: Razvan Cojocaru [mailto:pub@razie.com]
Sent: July-25-11 5:47 PM
To: 'HamsterofDeath'; scala-user@googlegroups.com
Subject: RE: [scala-user] i think i got it (monads and stuff)
He he – welcome to the world of mathematical abstractions J and types
What you call a monad is just a concept. What scala likes a monad to be is an object of type F[A] which implements this method:
def flatmap[B](f: A => F[B]): F[B]
where flatmap corresponds to Tony’s bind() and the class’s type constructor is the point().
You can see that Tony’s Monad trait below is not a proper scala monad, meaning it is not recognized in for comprehensions as being a monad. It is very useful however to decouple the scala syntax from the underlying concept.
In fact, in the trait below, the bind simply returns a function which does the binding… not the result.
Using the monad definition you started with, you need to make it scala friendly… I did not try to compile the code below but you should get the idea:
// scala friendly monad
trait ScalaMonad[F[_]] {
def flatmap[A, B](f: A => F[B]): F[B] // checkout the return value compared to the bind()
def map[A, B](f: A => B): F[B]
}
class ScalaMonadAdapter[F[_], M <: Monad[F]] (val container:F, val m:M) implements ScalaMonad {
def flatmap[A, B](f: A => F[B]): F[A] => F[B] = m.bind(f) (container)
def map[A, B](f: A => B): F[A] => F[B] = flatmap (point(f(_))) (container)
}
This pattern is used in scalaz to separate the actual monadic implementation from the underlying container or type. Another way to do it is to have your container derive the ScalaMonad trait
Dang, almost missed my train – have fun
RAzie
From: scala-user@googlegroups.com scala-user [at] googlegroups [dot] com]" rel="nofollow">[mailto:scala-user@googlegroups.com] On Behalf Of HamsterofDeath
Sent: July-25-11 3:28 PM
To: scala-user@googlegroups.com
Subject: Re: [scala-user] i think i got it (monads and stuff)
this doesn't make sense. i can't chain the bind-calls.
using option and any collection, i can do this:
a.map(_.toString).map(_toInt) and so on
using dumb functions i can do
a andThen b andThen c
how can i do this with the reader monad?
Am 25.07.2011 21:05, schrieb HamsterofDeath:
this might be a reader monad
class Reader[I] extends Monad2[({type M[O] = (I) => O})#M] {
def pure[A](a: A): (I) => A = (in:I) => a
def bind[A, B](m: (I) => A, f: A => ((I) => B)): (I) => B = (i:I) => f(m(i))(i)
}
it might help if i knew what it's supposed to do. this one just spits out functions that convert any I into and B and it ignores the input parameter at the "pure"-method which does not seem to make much sense.
Am 25.07.2011 20:05, schrieb HamsterofDeath:
this compiles:
trait Monad[F[_]] {
def point[A](a: => A): F[A]
def bind[A, B](f: A => F[B]): F[A] => F[B]
}
case class Identity[A](a: A)
object Monad {
val IdentityMonad: Monad[Identity] = new Monad[Identity] {
def bind[A, B](f: (A) => Identity[B]) = (e:Identity[A]) => f(e.a)
def point[A](a: => A) = Identity(a)
}
}
val identity = Monad.IdentityMonad.point("hi")
val transformer = Monad.IdentityMonad.bind((e: String) => Monad.IdentityMonad.point(e.toInt))
val wohoo = transformer.apply(identity)
Am 24.07.2011 23:10, schrieb Tony Morris:
> trait Monad[F[_]] {
> def point[A](a: => A): F[A]
> def bind[A, B](f: A => F[B]): F[A] => F[B]
> }
>
> case class Identity[A](a: A)
>
> object Monad {
> val IdentityMonad: Monad[Identity] = error("todo")
> }
Mon, 2011-07-25, 23:57
#14
Re: i think i got it (monads and stuff)
2011/7/25 HamsterofDeath <h-star@gmx.de>
the longer i look at this
trait Monad[M[_]] {
def bind[A, B](ma:M[A])(f:A => M[B]):M[B]
def unit[A](a:A):M[A]
def fmap[A, B](f:A => B):M[A] => M[B]
def ap[A, B](f:M[A => B]):M[A] => M[B]
}
the less sense it makes.
<snip/>
my brain refuses to see any sense in an implementation of a monad trait that does not return an instance of monad in the bind and unit method and accepts an instance of monad in the bind method.
Isn't it exactly what the trait does?
There are multiple angles. For example, if you look up the definition on wikipedia, you'll see that 'fmap' is closer to the description of a functor in category theory than the 'map' object method we typically implement in Scala in practice. I'm not saying you should study category theory (I only have some notions), but sometimes it helps to approach the same problem from different angles to gain a better understanding.
Here is another example. If you want more, I invite you to read the blog of Tony, you'll find several exercises in this vein. This is good for kata practice.
sealed abstract class Maybe[+A] {
def fold[B](empty: => B, just:A => B):B
}
case class Just[A](a:A) extends Maybe[A] {
def fold[B](empty: => B, just:A => B):B = just(a)
}
case object None extends Maybe[Nothing] {
def fold[B](empty: => B, just:Nothing => B):B = empty
}
implicit val maybeIsMonad = new Monad[Maybe] {
def bind[A, B](ma:Maybe[A])(f:A => Maybe[B]) = ma.fold(None, f)
def unit[A](a:A) = Just(a)
def fmap[A, B](f:A => B) = error("todo")
def ap[A, B](mf:Maybe[A => B]) = error("todo")
}
implicit def genericBox[M[_], A](ma:M[A])(implicit m:Monad[M]) = new MonadTrait[M, A] {
def flatMap[B](f:A => M[B]) = m.bind(ma)(f)
def map[B](f:A => B):M[B] = m.fmap(f)(ma)
}
for {
a <- Just(1):Maybe[Int]
b <- Just(a + 1):Maybe[Int]
} yield (a + b)
Cheers,
Sébastien
Tue, 2011-07-26, 00:17
#15
FW: i think i got it (monads and stuff)
I think that people coming from FP to scala see the world differently from people coming from OO to scala. Getting the answer to this particular question was a very important step for me, I think of it as crossing the Styx backwards J and unfortunately, have not seen this nicely laid out anywhere so far. Why Monad versus ScalaMonad versus just flatmap and how the heck is all this useful etc…
So to fully answer the HoD puzzle below, the Monad used by Tony is separate from the actual container F, so that you can use it on types you get from some library. I believe that scalaz uses that pattern, together with implicit conversions to make these look nice on the underlying containers. There be dragons - very advanced stuff there, well over my head and/or effort allotted J but I think I get the 10kfeet picture.
So, if you get a container C[_] from somewhere, you write the CM[C] monadic implementation for it and an implicit conversion and then some magic happens…
Check this out for a moment:
https://github.com/scalaz/scalaz/blob/master/core/src/main/scala/scalaz/Bind.scala
if I’m way off, I’m sure Tony will whack me over the head with some fmap or something J
cheers,
Razie
From: scala-user@googlegroups.com scala-user [at] googlegroups [dot] com]" rel="nofollow">[mailto:scala-user@googlegroups.com] On Behalf Of HamsterofDeath
Sent: July-25-11 5:39 PM
To: scala-user@googlegroups.com
Subject: Re: [scala-user] i think i got it (monads and stuff)
the longer i look at this
trait Monad[M[_]] {
def bind[A, B](ma:M[A])(f:A => M[B]):M[B]
def unit[A](a:A):M[A]
def fmap[A, B](f:A => B):M[A] => M[B]
def ap[A, B](f:M[A => B]):M[A] => M[B]
}
the less sense it makes.
i understand wrapping a:A in m:M[A].
i understand mapping M[A] to M[B]
simple.
i understand if you say "monad = both methods together", making a monad a utiliy object, not different from the well known *Utils-classes of java.
i understand how option works.
but i cannot make the mental jump to the monad trait. the implementation is nothing more than a function composer which i simply could do directly or via not-part-of-a-trait utility-methods if the logic is more complex.
my brain refuses to see any sense in an implementation of a monad trait that does not return an instance of monad in the bind and unit method and accepts an instance of monad in the bind method.
Am 25.07.2011 22:37, schrieb Sébastien Bocq:
I mean this is implementation specific.
2011/7/25 Sébastien Bocq <sebastien.bocq@gmail.com>
I'd like to know other opinions, but I find that avoiding OO makes it easier to reason about these abstract concepts in Scala. Here is my version of the identity monad:
trait Monad[M[_]] {
def bind[A, B](ma:M[A])(f:A => M[B]):M[B]
def unit[A](a:A):M[A]
def fmap[A, B](f:A => B):M[A] => M[B]
def ap[A, B](f:M[A => B]):M[A] => M[B]
}
type Id[A] = A
implicit val mId = new Monad[Id] {
def bind[A, B](a:Id[A])(f:A => Id[B]) = f(a)
def unit[A](a:A) = a
def fmap[A, B](f:A => B) = f
def ap[A, B](f:Id[A => B]) = f
}
(See how identity fmap a function to itself.)
Now you can box the monad inside an object to use it in a for-comprehension but this is incidental (I'm wondering if the boxing is optimized away by the JVM).
trait MonadTrait[M[_], A] {
def flatMap[B](f:A => M[B]):M[B]
def map[B](f:A => B):M[B]
}
implicit def idBox[A](ma:Id[A])(implicit m:Monad[Id]) = new MonadTrait[Id, A] {
def flatMap[B](f:A => Id[B]) = m.bind(ma)(f)
def map[B](f:A => B):Id[B] = m.fmap(f)(ma)
}
def test(x:Id[Int]) = for {
y <- x * x
z <- y + y
} yield (y + z)
println(test(42))
Have fun!
2011/7/25 HamsterofDeath <h-star@gmx.de>
this compiles:
trait Monad[F[_]] {
def point[A](a: => A): F[A]
def bind[A, B](f: A => F[B]): F[A] => F[B]
}
case class Identity[A](a: A)
object Monad {
val IdentityMonad: Monad[Identity] = new Monad[Identity] {
def bind[A, B](f: (A) => Identity[B]) = (e:Identity[A]) => f(e.a)
def point[A](a: => A) = Identity(a)
}
}
val identity = Monad.IdentityMonad.point("hi")
val transformer = Monad.IdentityMonad.bind((e: String) => Monad.IdentityMonad.point(e.toInt))
val wohoo = transformer.apply(identity)
Am 24.07.2011 23:10, schrieb Tony Morris:
> trait Monad[F[_]] {
> def point[A](a: => A): F[A]
> def bind[A, B](f: A => F[B]): F[A] => F[B]
> }
>
> case class Identity[A](a: A)
>
> object Monad {
> val IdentityMonad: Monad[Identity] = error("todo")
> }
--
Sébastien
--
Sébastien
Tue, 2011-07-26, 00:37
#16
Re: FW: i think i got it (monads and stuff)
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
There's nothing too foreign here to anyone coming from Java. There is
higher-order polymorphism and a bit more discipline in the types. The
rest is already familiar. The Monad interface is just that -- an
interface. Interfaces are implemented by various data structures, in
this case, type constructors. They give rise to useful operations as a
result.
Here is one such operation:
// top of my head, may not compile!
def sequence[F[_], A](x: List[F[A]], m: Monad[F]): F[List[A]] =
x match {
case Nil => m.point(Nil)
case h::t => m.bind(hh => m.bind(tt => m.point(hh::tt))(t))(h)
} // can be written a bit neater using foldRight
Here is another:
def filterM[F[_], A](p: A => F[Boolean], x: List[A], m: Monad[F]):
F[List[A]] = error("readers exercise")
Of course you can then do fancy things with implicits and that Monad
argument.
PS: I am very much against calling the type constructor a "container"
for the purposes of teaching.
On 26/07/11 08:58, Razvan Cojocaru wrote:
> I think that people coming from FP to scala see the world
> differently from people coming from OO to scala. Getting the answer
> to this particular question was a very important step for me, I
> think of it as crossing the Styx backwards J and unfortunately,
> have not seen this nicely laid out anywhere so far. Why Monad
> versus ScalaMonad versus just flatmap and how the heck is all this
> useful etc?
>
>
>
> So to fully answer the HoD puzzle below, the Monad used by Tony is
> separate from the actual container F, so that you can use it on
> types you get from some library. I believe that scalaz uses that
> pattern, together with implicit conversions to make these look nice
> on the underlying containers. There be dragons - very advanced
> stuff there, well over my head and/or effort allotted J but I think
> I get the 10kfeet picture.
>
>
>
> So, if you get a container C[_] from somewhere, you write the CM[C]
> monadic implementation for it and an implicit conversion and then
> some magic happens?
>
>
>
> Check this out for a moment:
>
>
>
> https://github.com/scalaz/scalaz/blob/master/core/src/main/scala/scalaz/...
>
>
.scala
>
>
>
> if I?m way off, I?m sure Tony will whack me over the head with some
> fmap or something J
>
>
>
> cheers,
>
> Razie
>
>
>
> From: scala-user@googlegroups.com
> [mailto:scala-user@googlegroups.com] On Behalf Of HamsterofDeath
> Sent: July-25-11 5:39 PM To: scala-user@googlegroups.com Subject:
> Re: [scala-user] i think i got it (monads and stuff)
>
>
>
> the longer i look at this trait Monad[M[_]] { def bind[A,
> B](ma:M[A])(f:A => M[B]):M[B] def unit[A](a:A):M[A] def fmap[A,
> B](f:A => B):M[A] => M[B] def ap[A, B](f:M[A => B]):M[A] => M[B] }
> the less sense it makes.
>
> i understand wrapping a:A in m:M[A]. i understand mapping M[A] to
> M[B] simple. i understand if you say "monad = both methods
> together", making a monad a utiliy object, not different from the
> well known *Utils-classes of java. i understand how option works.
> but i cannot make the mental jump to the monad trait. the
> implementation is nothing more than a function composer which i
> simply could do directly or via not-part-of-a-trait utility-methods
> if the logic is more complex. my brain refuses to see any sense in
> an implementation of a monad trait that does not return an instance
> of monad in the bind and unit method and accepts an instance of
> monad in the bind method.
>
>
> Am 25.07.2011 22:37, schrieb Sébastien Bocq:
>
> I mean this is implementation specific.
>
> 2011/7/25 Sébastien Bocq
>
> I'd like to know other opinions, but I find that avoiding OO makes
> it easier to reason about these abstract concepts in Scala. Here is
> my version of the identity monad:
>
> trait Monad[M[_]] { def bind[A, B](ma:M[A])(f:A => M[B]):M[B] def
> unit[A](a:A):M[A] def fmap[A, B](f:A => B):M[A] => M[B] def ap[A,
> B](f:M[A => B]):M[A] => M[B] }
>
> type Id[A] = A
>
> implicit val mId = new Monad[Id] { def bind[A, B](a:Id[A])(f:A =>
> Id[B]) = f(a) def unit[A](a:A) = a def fmap[A, B](f:A => B) = f def
> ap[A, B](f:Id[A => B]) = f }
>
> (See how identity fmap a function to itself.)
>
> Now you can box the monad inside an object to use it in a
> for-comprehension but this is incidental (I'm wondering if the
> boxing is optimized away by the JVM).
>
> trait MonadTrait[M[_], A] { def flatMap[B](f:A => M[B]):M[B] def
> map[B](f:A => B):M[B] }
>
> implicit def idBox[A](ma:Id[A])(implicit m:Monad[Id]) = new
> MonadTrait[Id, A] { def flatMap[B](f:A => Id[B]) = m.bind(ma)(f)
> def map[B](f:A => B):Id[B] = m.fmap(f)(ma) }
>
> def test(x:Id[Int]) = for { y <- x * x z <- y + y } yield (y + z)
>
> println(test(42))
>
> Have fun!
>
>
>
> 2011/7/25 HamsterofDeath
>
> this compiles: trait Monad[F[_]] { def point[A](a: => A): F[A]
>
> def bind[A, B](f: A => F[B]): F[A] => F[B] }
>
> case class Identity[A](a: A)
>
> object Monad { val IdentityMonad: Monad[Identity] = new
> Monad[Identity] { def bind[A, B](f: (A) => Identity[B]) =
> (e:Identity[A]) => f(e.a)
>
> def point[A](a: => A) = Identity(a) } }
>
> val identity = Monad.IdentityMonad.point("hi") val transformer =
> Monad.IdentityMonad.bind((e: String) =>
> Monad.IdentityMonad.point(e.toInt)) val wohoo =
> transformer.apply(identity)
>
>
> Am 24.07.2011 23:10, schrieb Tony Morris:
>> trait Monad[F[_]] { def point[A](a: => A): F[A] def bind[A, B](f:
>> A => F[B]): F[A] => F[B] }
>>
>> case class Identity[A](a: A)
>>
>> object Monad { val IdentityMonad: Monad[Identity] = error("todo")
>> }
>
>
>
>
>
>
Tue, 2011-07-26, 00:47
#17
Re: FW: i think i got it (monads and stuff)
Dear Tony,
i agree -- in principle -- that thinking of the functor underlying the monad as a container can be limiting -- precisely because it can later be confusing when we generalize to control. However, what can be shown is that the syntactic view is canonical. For example, thinking of monads as colored braces is canonical and aligns with people's intuitions about XML. So bootstrapping an understanding in this way is provably sound.
Philosophically, it's even more important to understand that every model factors through a syntactic presentation because
You raise a good point regarding OO. i observe that at least twice, now, OO has lead the Scala design team down the primrose path. The first is the way the for-comprehensions syntax maps to the underlying interface -- which doesn't make the separation between data structure and API that it ought to. The second is the way inheritance is misused to address the relationship between collection and function. In both cases the failing is actually a failing to take OO principles far enough and make important contextual information into computational entities.
Best wishes,
--greg
On Mon, Jul 25, 2011 at 4:20 PM, Tony Morris <tonymorris@gmail.com> wrote:
--
L.G. Meredith
Managing Partner
Biosimilarity LLC
7329 39th Ave SWSeattle, WA 98136
+1 206.650.3740
http://biosimilarity.blogspot.com
i agree -- in principle -- that thinking of the functor underlying the monad as a container can be limiting -- precisely because it can later be confusing when we generalize to control. However, what can be shown is that the syntactic view is canonical. For example, thinking of monads as colored braces is canonical and aligns with people's intuitions about XML. So bootstrapping an understanding in this way is provably sound.
Philosophically, it's even more important to understand that every model factors through a syntactic presentation because
- that is the essence of the computational interpretation of monads -- they reify computation
- our only handle on control is via syntax -- we have to manipulate the infinitary objects of computation through (something equivalent to) source code -- that's our only way to grab a computation and treat it as data
You raise a good point regarding OO. i observe that at least twice, now, OO has lead the Scala design team down the primrose path. The first is the way the for-comprehensions syntax maps to the underlying interface -- which doesn't make the separation between data structure and API that it ought to. The second is the way inheritance is misused to address the relationship between collection and function. In both cases the failing is actually a failing to take OO principles far enough and make important contextual information into computational entities.
Best wishes,
--greg
On Mon, Jul 25, 2011 at 4:20 PM, Tony Morris <tonymorris@gmail.com> wrote:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
There's nothing too foreign here to anyone coming from Java. There is
higher-order polymorphism and a bit more discipline in the types. The
rest is already familiar. The Monad interface is just that -- an
interface. Interfaces are implemented by various data structures, in
this case, type constructors. They give rise to useful operations as a
result.
Here is one such operation:
// top of my head, may not compile!
def sequence[F[_], A](x: List[F[A]], m: Monad[F]): F[List[A]] =
x match {
case Nil => m.point(Nil)
case h::t => m.bind(hh => m.bind(tt => m.point(hh::tt))(t))(h)
} // can be written a bit neater using foldRight
Here is another:
def filterM[F[_], A](p: A => F[Boolean], x: List[A], m: Monad[F]):
F[List[A]] = error("readers exercise")
Of course you can then do fancy things with implicits and that Monad
argument.
PS: I am very much against calling the type constructor a "container"
for the purposes of teaching.
On 26/07/11 08:58, Razvan Cojocaru wrote:
> I think that people coming from FP to scala see the world
> differently from people coming from OO to scala. Getting the answer
> to this particular question was a very important step for me, I
> think of it as crossing the Styx backwards J and unfortunately,
> have not seen this nicely laid out anywhere so far. Why Monad
> versus ScalaMonad versus just flatmap and how the heck is all this
> useful etc?
>
>
>
> So to fully answer the HoD puzzle below, the Monad used by Tony is
> separate from the actual container F, so that you can use it on
> types you get from some library. I believe that scalaz uses that
> pattern, together with implicit conversions to make these look nice
> on the underlying containers. There be dragons - very advanced
> stuff there, well over my head and/or effort allotted J but I think
> I get the 10kfeet picture.
>
>
>
> So, if you get a container C[_] from somewhere, you write the CM[C]
> monadic implementation for it and an implicit conversion and then
> some magic happens?
>
>
>
> Check this out for a moment:
>
>
>
> https://github.com/scalaz/scalaz/blob/master/core/src/main/scala/scalaz/Bind
>
>
.scala
>
>
>
> if I?m way off, I?m sure Tony will whack me over the head with some
> fmap or something J
>
>
>
> cheers,
>
> Razie
>
>
>
> From: scala-user@googlegroups.com
> [mailto:scala-user@googlegroups.com] On Behalf Of HamsterofDeath
> Sent: July-25-11 5:39 PM To: scala-user@googlegroups.com Subject:
> Re: [scala-user] i think i got it (monads and stuff)
>
>
>
> the longer i look at this trait Monad[M[_]] { def bind[A,
> B](ma:M[A])(f:A => M[B]):M[B] def unit[A](a:A):M[A] def fmap[A,
> B](f:A => B):M[A] => M[B] def ap[A, B](f:M[A => B]):M[A] => M[B] }
> the less sense it makes.
>
> i understand wrapping a:A in m:M[A]. i understand mapping M[A] to
> M[B] simple. i understand if you say "monad = both methods
> together", making a monad a utiliy object, not different from the
> well known *Utils-classes of java. i understand how option works.
> but i cannot make the mental jump to the monad trait. the
> implementation is nothing more than a function composer which i
> simply could do directly or via not-part-of-a-trait utility-methods
> if the logic is more complex. my brain refuses to see any sense in
> an implementation of a monad trait that does not return an instance
> of monad in the bind and unit method and accepts an instance of
> monad in the bind method.
>
>
> Am 25.07.2011 22:37, schrieb Sébastien Bocq:
>
> I mean this is implementation specific.
>
> 2011/7/25 Sébastien Bocq <sebastien.bocq@gmail.com>
>
> I'd like to know other opinions, but I find that avoiding OO makes
> it easier to reason about these abstract concepts in Scala. Here is
> my version of the identity monad:
>
> trait Monad[M[_]] { def bind[A, B](ma:M[A])(f:A => M[B]):M[B] def
> unit[A](a:A):M[A] def fmap[A, B](f:A => B):M[A] => M[B] def ap[A,
> B](f:M[A => B]):M[A] => M[B] }
>
> type Id[A] = A
>
> implicit val mId = new Monad[Id] { def bind[A, B](a:Id[A])(f:A =>
> Id[B]) = f(a) def unit[A](a:A) = a def fmap[A, B](f:A => B) = f def
> ap[A, B](f:Id[A => B]) = f }
>
> (See how identity fmap a function to itself.)
>
> Now you can box the monad inside an object to use it in a
> for-comprehension but this is incidental (I'm wondering if the
> boxing is optimized away by the JVM).
>
> trait MonadTrait[M[_], A] { def flatMap[B](f:A => M[B]):M[B] def
> map[B](f:A => B):M[B] }
>
> implicit def idBox[A](ma:Id[A])(implicit m:Monad[Id]) = new
> MonadTrait[Id, A] { def flatMap[B](f:A => Id[B]) = m.bind(ma)(f)
> def map[B](f:A => B):Id[B] = m.fmap(f)(ma) }
>
> def test(x:Id[Int]) = for { y <- x * x z <- y + y } yield (y + z)
>
> println(test(42))
>
> Have fun!
>
>
>
> 2011/7/25 HamsterofDeath <h-star@gmx.de>
>
> this compiles: trait Monad[F[_]] { def point[A](a: => A): F[A]
>
> def bind[A, B](f: A => F[B]): F[A] => F[B] }
>
> case class Identity[A](a: A)
>
> object Monad { val IdentityMonad: Monad[Identity] = new
> Monad[Identity] { def bind[A, B](f: (A) => Identity[B]) =
> (e:Identity[A]) => f(e.a)
>
> def point[A](a: => A) = Identity(a) } }
>
> val identity = Monad.IdentityMonad.point("hi") val transformer =
> Monad.IdentityMonad.bind((e: String) =>
> Monad.IdentityMonad.point(e.toInt)) val wohoo =
> transformer.apply(identity)
>
>
> Am 24.07.2011 23:10, schrieb Tony Morris:
>> trait Monad[F[_]] { def point[A](a: => A): F[A] def bind[A, B](f:
>> A => F[B]): F[A] => F[B] }
>>
>> case class Identity[A](a: A)
>>
>> object Monad { val IdentityMonad: Monad[Identity] = error("todo")
>> }
>
>
>
>
>
>
- --
Tony Morris
http://tmorris.net/
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/
iEYEARECAAYFAk4t+icACgkQmnpgrYe6r62kKwCglTF6+LFG7KojSNkPmvKE3e5X
y0IAn3TweSrNsrQjK1Wx+XEEy5g2fTaM
=VSNT
-----END PGP SIGNATURE-----
--
L.G. Meredith
Managing Partner
Biosimilarity LLC
7329 39th Ave SWSeattle, WA 98136
+1 206.650.3740
http://biosimilarity.blogspot.com
Tue, 2011-07-26, 00:57
#18
Re: i think i got it (monads and stuff)
Coming back to the Identity monad, this version makes it even more apparent:
trait Monad[M[_]] {
def bind[A, B](f:A => M[B]):M[A] => M[B]
def unit[A]:A => M[A]
def fmap[A, B](f:A => B):M[A] => M[B]
def ap[A, B](f:M[A => B]):M[A] => M[B]
}
type Id[A] = A
implicit val m = new Monad[Id] {
def bind[A, B](f:A => Id[B]) = f
def unit[A] = identity // Tada!
def fmap[A, B](f:A => B) = f
def ap[A, B](f:Id[A => B]) = f
}
2011/7/25 Sébastien Bocq <sebastien.bocq@gmail.com>
--
Sébastien
trait Monad[M[_]] {
def bind[A, B](f:A => M[B]):M[A] => M[B]
def unit[A]:A => M[A]
def fmap[A, B](f:A => B):M[A] => M[B]
def ap[A, B](f:M[A => B]):M[A] => M[B]
}
type Id[A] = A
implicit val m = new Monad[Id] {
def bind[A, B](f:A => Id[B]) = f
def unit[A] = identity // Tada!
def fmap[A, B](f:A => B) = f
def ap[A, B](f:Id[A => B]) = f
}
2011/7/25 Sébastien Bocq <sebastien.bocq@gmail.com>
I'd like to know other opinions, but I find that avoiding OO makes it easier to reason about these abstract concepts in Scala. Here is my version of the identity monad:
trait Monad[M[_]] {
def bind[A, B](ma:M[A])(f:A => M[B]):M[B]
def unit[A](a:A):M[A]
def fmap[A, B](f:A => B):M[A] => M[B]
def ap[A, B](f:M[A => B]):M[A] => M[B]
}
type Id[A] = A
implicit val mId = new Monad[Id] {
def bind[A, B](a:Id[A])(f:A => Id[B]) = f(a)
def unit[A](a:A) = a
def fmap[A, B](f:A => B) = f
def ap[A, B](f:Id[A => B]) = f
}
(See how identity fmap a function to itself.)
Now you can box the monad inside an object to use it in a for-comprehension but this is incidental (I'm wondering if the boxing is optimized away by the JVM).
trait MonadTrait[M[_], A] {
def flatMap[B](f:A => M[B]):M[B]
def map[B](f:A => B):M[B]
}
implicit def idBox[A](ma:Id[A])(implicit m:Monad[Id]) = new MonadTrait[Id, A] {
def flatMap[B](f:A => Id[B]) = m.bind(ma)(f)
def map[B](f:A => B):Id[B] = m.fmap(f)(ma)
}
def test(x:Id[Int]) = for {
y <- x * x
z <- y + y
} yield (y + z)
println(test(42))
Have fun!
2011/7/25 HamsterofDeath <h-star@gmx.de>this compiles:
trait Monad[F[_]] {
def point[A](a: => A): F[A]
def bind[A, B](f: A => F[B]): F[A] => F[B]
}
case class Identity[A](a: A)
object Monad {
val IdentityMonad: Monad[Identity] = new Monad[Identity] {
def bind[A, B](f: (A) => Identity[B]) = (e:Identity[A]) => f(e.a)
def point[A](a: => A) = Identity(a)
}
}
val identity = Monad.IdentityMonad.point("hi")
val transformer = Monad.IdentityMonad.bind((e: String) => Monad.IdentityMonad.point(e.toInt))
val wohoo = transformer.apply(identity)
Am 24.07.2011 23:10, schrieb Tony Morris:
> trait Monad[F[_]] {
> def point[A](a: => A): F[A]
> def bind[A, B](f: A => F[B]): F[A] => F[B]
> }
>
> case class Identity[A](a: A)
>
> object Monad {
> val IdentityMonad: Monad[Identity] = error("todo")
> }
--
Sébastien
--
Sébastien
Tue, 2011-07-26, 01:17
#19
Re: i think i got it (monads and stuff)
Dear Sebastien, et al,
With this implementation you still need a for-comprehension shiv. i've been experimenting with a dog-leg arrangement where the monad houses a wrapper that implements the for-comprehension traits using the monadic methods and the monad implements a version of apply taking the collection to the shiv. So, for
val mnd = Monad[M]val m = M[A]( ... )
for( a <- mnd( m ) ) { // do something here ...}
One advantage of this arrangement is that you have lexical reminder which monad is in operation. It intentionally avoids the implicit. Thoughts? Comments?
Best wishes,
--greg
On Mon, Jul 25, 2011 at 4:42 PM, Sébastien Bocq <sebastien.bocq@gmail.com> wrote:
--
L.G. Meredith
Managing Partner
Biosimilarity LLC
7329 39th Ave SWSeattle, WA 98136
+1 206.650.3740
http://biosimilarity.blogspot.com
With this implementation you still need a for-comprehension shiv. i've been experimenting with a dog-leg arrangement where the monad houses a wrapper that implements the for-comprehension traits using the monadic methods and the monad implements a version of apply taking the collection to the shiv. So, for
val mnd = Monad[M]val m = M[A]( ... )
for( a <- mnd( m ) ) { // do something here ...}
One advantage of this arrangement is that you have lexical reminder which monad is in operation. It intentionally avoids the implicit. Thoughts? Comments?
Best wishes,
--greg
On Mon, Jul 25, 2011 at 4:42 PM, Sébastien Bocq <sebastien.bocq@gmail.com> wrote:
Coming back to the Identity monad, this version makes it even more apparent:
trait Monad[M[_]] {
def bind[A, B](f:A => M[B]):M[A] => M[B]
def unit[A]:A => M[A]
def fmap[A, B](f:A => B):M[A] => M[B]
def ap[A, B](f:M[A => B]):M[A] => M[B]
}
type Id[A] = A
implicit val m = new Monad[Id] {
def bind[A, B](f:A => Id[B]) = f
def unit[A] = identity // Tada!
def fmap[A, B](f:A => B) = f
def ap[A, B](f:Id[A => B]) = f
}
2011/7/25 Sébastien Bocq <sebastien.bocq@gmail.com>
I'd like to know other opinions, but I find that avoiding OO makes it easier to reason about these abstract concepts in Scala. Here is my version of the identity monad:
trait Monad[M[_]] {
def bind[A, B](ma:M[A])(f:A => M[B]):M[B]
def unit[A](a:A):M[A]
def fmap[A, B](f:A => B):M[A] => M[B]
def ap[A, B](f:M[A => B]):M[A] => M[B]
}
type Id[A] = A
implicit val mId = new Monad[Id] {
def bind[A, B](a:Id[A])(f:A => Id[B]) = f(a)
def unit[A](a:A) = a
def fmap[A, B](f:A => B) = f
def ap[A, B](f:Id[A => B]) = f
}
(See how identity fmap a function to itself.)
Now you can box the monad inside an object to use it in a for-comprehension but this is incidental (I'm wondering if the boxing is optimized away by the JVM).
trait MonadTrait[M[_], A] {
def flatMap[B](f:A => M[B]):M[B]
def map[B](f:A => B):M[B]
}
implicit def idBox[A](ma:Id[A])(implicit m:Monad[Id]) = new MonadTrait[Id, A] {
def flatMap[B](f:A => Id[B]) = m.bind(ma)(f)
def map[B](f:A => B):Id[B] = m.fmap(f)(ma)
}
def test(x:Id[Int]) = for {
y <- x * x
z <- y + y
} yield (y + z)
println(test(42))
Have fun!
2011/7/25 HamsterofDeath <h-star@gmx.de>this compiles:
trait Monad[F[_]] {
def point[A](a: => A): F[A]
def bind[A, B](f: A => F[B]): F[A] => F[B]
}
case class Identity[A](a: A)
object Monad {
val IdentityMonad: Monad[Identity] = new Monad[Identity] {
def bind[A, B](f: (A) => Identity[B]) = (e:Identity[A]) => f(e.a)
def point[A](a: => A) = Identity(a)
}
}
val identity = Monad.IdentityMonad.point("hi")
val transformer = Monad.IdentityMonad.bind((e: String) => Monad.IdentityMonad.point(e.toInt))
val wohoo = transformer.apply(identity)
Am 24.07.2011 23:10, schrieb Tony Morris:
> trait Monad[F[_]] {
> def point[A](a: => A): F[A]
> def bind[A, B](f: A => F[B]): F[A] => F[B]
> }
>
> case class Identity[A](a: A)
>
> object Monad {
> val IdentityMonad: Monad[Identity] = error("todo")
> }
--
Sébastien
--
Sébastien
--
L.G. Meredith
Managing Partner
Biosimilarity LLC
7329 39th Ave SWSeattle, WA 98136
+1 206.650.3740
http://biosimilarity.blogspot.com
Tue, 2011-07-26, 04:27
#20
RE: FW: i think i got it (monads and stuff)
The “container” thing slipped… but it did actually help me I think initially to descope the abstracts.
Indeed, about OO, monads and Java – there’s a lot to be said. The most important I think is the domain modeling aspect. An OO person understands that concepts map to objects and these are usable. Plain old limited UML. But when you say Monad – it is not it! It’s just a reflection of a part of the underlying thing, because everyone says “the List Monad” and that “List is a monad” and then we see the Monad trait and it’s not useful by itself… and then you’re tweaking it even further (now I understand why) so that bind () returns not even a thing but a thing to later give me a thing!!! Ahh, the laziness!
It’s a big impedance mismatch… as an OOpist, I need to “dot something”… I don’t have a “dot something”. When you say “it’s a Monad” well, I expect it to derive from it at some point and actually be one, but it doesn’t. Ahhh!!! J
There’s a bunch of other stuff on top of that, you need to make this pattern work:
- higher functions – I’m lucky to have an extensive C++ background where you could pass methods (well, pointers to)
- Type parametrization – fairly new in Java really… again C++ background helps
- Higher kinds – opa.
- Implicits – again lucky with C++, although different, I have a feel for it
- Duck typing – in the implementation of the for comprehension… opa! This is probably the least OO-friendly here
- Usefulness which is really apparent in the for comprehension and similar syntax, just because chaining flatmaps is so not obvious J
Seriously, there’s a lot of moving parts to this. Once you get past the initial shock and separate the (mathematical) concept, it’s usefulness and its possibly different representations in scala or whathave you and the respective techniques, it’s different and that’s the crossing of the Styx I was talking about.
I don’t want to go down another “OMG, scala is complex” because it’s not, just want to point that the implicit implementation in C++ is somehow more aligned with an OO mindset than the one in scala. I understand the limitations, but still… the impedance mismatch. All these impedance mismatches are like pairs of glasses that add to make the picture that much more distorted and hard to understand.
Greg – as you know, I find your colored braces approach with the shape and roll, very useful.
Cheers,
Razie
From: scala-user@googlegroups.com [mailto:scala-user@googlegroups.com] On Behalf Of Meredith Gregory
Sent: July-25-11 7:36 PM
To: tmorris@tmorris.net
Cc: scala-user@googlegroups.com
Subject: Re: FW: [scala-user] i think i got it (monads and stuff)
Dear Tony,
i agree -- in principle -- that thinking of the functor underlying the monad as a container can be limiting -- precisely because it can later be confusing when we generalize to control. However, what can be shown is that the syntactic view is canonical. For example, thinking of monads as colored braces is canonical and aligns with people's intuitions about XML. So bootstrapping an understanding in this way is provably sound.
Philosophically, it's even more important to understand that every model factors through a syntactic presentation because
- that is the essence of the computational interpretation of monads -- they reify computation
- our only handle on control is via syntax -- we have to manipulate the infinitary objects of computation through (something equivalent to) source code -- that's our only way to grab a computation and treat it as data
Dear Razie,
You raise a good point regarding OO. i observe that at least twice, now, OO has lead the Scala design team down the primrose path. The first is the way the for-comprehensions syntax maps to the underlying interface -- which doesn't make the separation between data structure and API that it ought to. The second is the way inheritance is misused to address the relationship between collection and function. In both cases the failing is actually a failing to take OO principles far enough and make important contextual information into computational entities.
Best wishes,
--greg
On Mon, Jul 25, 2011 at 4:20 PM, Tony Morris <tonymorris@gmail.com> wrote:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
There's nothing too foreign here to anyone coming from Java. There is
higher-order polymorphism and a bit more discipline in the types. The
rest is already familiar. The Monad interface is just that -- an
interface. Interfaces are implemented by various data structures, in
this case, type constructors. They give rise to useful operations as a
result.
Here is one such operation:
// top of my head, may not compile!
def sequence[F[_], A](x: List[F[A]], m: Monad[F]): F[List[A]] =
x match {
case Nil => m.point(Nil)
case h::t => m.bind(hh => m.bind(tt => m.point(hh::tt))(t))(h)
} // can be written a bit neater using foldRight
Here is another:
def filterM[F[_], A](p: A => F[Boolean], x: List[A], m: Monad[F]):
F[List[A]] = error("readers exercise")
Of course you can then do fancy things with implicits and that Monad
argument.
PS: I am very much against calling the type constructor a "container"
for the purposes of teaching.
On 26/07/11 08:58, Razvan Cojocaru wrote:
> I think that people coming from FP to scala see the world
> differently from people coming from OO to scala. Getting the answer
> to this particular question was a very important step for me, I
> think of it as crossing the Styx backwards J and unfortunately,
> have not seen this nicely laid out anywhere so far. Why Monad
> versus ScalaMonad versus just flatmap and how the heck is all this
> useful etc?
>
>
>
> So to fully answer the HoD puzzle below, the Monad used by Tony is
> separate from the actual container F, so that you can use it on
> types you get from some library. I believe that scalaz uses that
> pattern, together with implicit conversions to make these look nice
> on the underlying containers. There be dragons - very advanced
> stuff there, well over my head and/or effort allotted J but I think
> I get the 10kfeet picture.
>
>
>
> So, if you get a container C[_] from somewhere, you write the CM[C]
> monadic implementation for it and an implicit conversion and then
> some magic happens?
>
>
>
> Check this out for a moment:
>
>
>
> https://github.com/scalaz/scalaz/blob/master/core/src/main/scala/scalaz/Bind
>
>
.scala
>
>
>
> if I?m way off, I?m sure Tony will whack me over the head with some
> fmap or something J
>
>
>
> cheers,
>
> Razie
>
>
>
> From: scala-user@googlegroups.com
> [mailto:scala-user@googlegroups.com] On Behalf Of HamsterofDeath
> Sent: July-25-11 5:39 PM To: scala-user@googlegroups.com Subject:
> Re: [scala-user] i think i got it (monads and stuff)
>
>
>
> the longer i look at this trait Monad[M[_]] { def bind[A,
> B](ma:M[A])(f:A => M[B]):M[B] def unit[A](a:A):M[A] def fmap[A,
> B](f:A => B):M[A] => M[B] def ap[A, B](f:M[A => B]):M[A] => M[B] }
> the less sense it makes.
>
> i understand wrapping a:A in m:M[A]. i understand mapping M[A] to
> M[B] simple. i understand if you say "monad = both methods
> together", making a monad a utiliy object, not different from the
> well known *Utils-classes of java. i understand how option works.
> but i cannot make the mental jump to the monad trait. the
> implementation is nothing more than a function composer which i
> simply could do directly or via not-part-of-a-trait utility-methods
> if the logic is more complex. my brain refuses to see any sense in
> an implementation of a monad trait that does not return an instance
> of monad in the bind and unit method and accepts an instance of
> monad in the bind method.
>
>
> Am 25.07.2011 22:37, schrieb Sébastien Bocq:
>
> I mean this is implementation specific.
>
> 2011/7/25 Sébastien Bocq <sebastien.bocq@gmail.com>
>
> I'd like to know other opinions, but I find that avoiding OO makes
> it easier to reason about these abstract concepts in Scala. Here is
> my version of the identity monad:
>
> trait Monad[M[_]] { def bind[A, B](ma:M[A])(f:A => M[B]):M[B] def
> unit[A](a:A):M[A] def fmap[A, B](f:A => B):M[A] => M[B] def ap[A,
> B](f:M[A => B]):M[A] => M[B] }
>
> type Id[A] = A
>
> implicit val mId = new Monad[Id] { def bind[A, B](a:Id[A])(f:A =>
> Id[B]) = f(a) def unit[A](a:A) = a def fmap[A, B](f:A => B) = f def
> ap[A, B](f:Id[A => B]) = f }
>
> (See how identity fmap a function to itself.)
>
> Now you can box the monad inside an object to use it in a
> for-comprehension but this is incidental (I'm wondering if the
> boxing is optimized away by the JVM).
>
> trait MonadTrait[M[_], A] { def flatMap[B](f:A => M[B]):M[B] def
> map[B](f:A => B):M[B] }
>
> implicit def idBox[A](ma:Id[A])(implicit m:Monad[Id]) = new
> MonadTrait[Id, A] { def flatMap[B](f:A => Id[B]) = m.bind(ma)(f)
> def map[B](f:A => B):Id[B] = m.fmap(f)(ma) }
>
> def test(x:Id[Int]) = for { y <- x * x z <- y + y } yield (y + z)
>
> println(test(42))
>
> Have fun!
>
>
>
> 2011/7/25 HamsterofDeath <h-star@gmx.de>
>
> this compiles: trait Monad[F[_]] { def point[A](a: => A): F[A]
>
> def bind[A, B](f: A => F[B]): F[A] => F[B] }
>
> case class Identity[A](a: A)
>
> object Monad { val IdentityMonad: Monad[Identity] = new
> Monad[Identity] { def bind[A, B](f: (A) => Identity[B]) =
> (e:Identity[A]) => f(e.a)
>
> def point[A](a: => A) = Identity(a) } }
>
> val identity = Monad.IdentityMonad.point("hi") val transformer =
> Monad.IdentityMonad.bind((e: String) =>
> Monad.IdentityMonad.point(e.toInt)) val wohoo =
> transformer.apply(identity)
>
>
> Am 24.07.2011 23:10, schrieb Tony Morris:
>> trait Monad[F[_]] { def point[A](a: => A): F[A] def bind[A, B](f:
>> A => F[B]): F[A] => F[B] }
>>
>> case class Identity[A](a: A)
>>
>> object Monad { val IdentityMonad: Monad[Identity] = error("todo")
>> }
>
>
>
>
>
>
- --
Tony Morris
http://tmorris.net/
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/
iEYEARECAAYFAk4t+icACgkQmnpgrYe6r62kKwCglTF6+LFG7KojSNkPmvKE3e5X
y0IAn3TweSrNsrQjK1Wx+XEEy5g2fTaM
=VSNT
-----END PGP SIGNATURE-----
--
L.G. Meredith
Managing Partner
Biosimilarity LLC
7329 39th Ave SW
Seattle, WA 98136
+1 206.650.3740
http://biosimilarity.blogspot.com
Tue, 2011-07-26, 06:57
#21
Re: i think i got it (monads and stuff)
ZfJypY9AC_KYJFsEqmS1Gkt9OR7q9MhYcOw [at] mail [dot] gmail [dot] com" type="cite">trait Monad[M[_]] {
def bind[A, B](ma:M[A])(f:A => M[B]):M[B]
def unit[A](a:A):M[A]
def fmap[A, B](f:A => B):M[A] => M[B]
def ap[A, B](f:M[A => B]):M[A] => M[B]
}
the less sense it makes.
<snip/>
my brain refuses to see any sense in an implementation of a monad trait that does not return an instance of monad in the bind and unit method and accepts an instance of monad in the bind method.
Isn't it exactly what the trait does?
no, it's not. it returns functions that can convert M[A] into M[B], not Monad[A] into Monad[B] - unless you declare M as M <: Monad[_]
Tue, 2011-07-26, 07:57
#22
Re: i think i got it (monads and stuff)
2011/7/26 HamsterofDeath <h-star@gmx.de>
trait Monad[M[_]] {
def bind[A, B](ma:M[A])(f:A => M[B]):M[B]
def unit[A](a:A):M[A]
def fmap[A, B](f:A => B):M[A] => M[B]
def ap[A, B](f:M[A => B]):M[A] => M[B]
}
the less sense it makes.
<snip/>
my brain refuses to see any sense in an implementation of a monad trait that does not return an instance of monad in the bind and unit method and accepts an instance of monad in the bind method.
Isn't it exactly what the trait does?
no, it's not. it returns functions that can convert M[A] into M[B], not Monad[A] into Monad[B] - unless you declare M as M <: Monad[_]
Ok, I see what you mean. The inheritance constraint doesn't add any bit of useful information. If you can successfully define the methods bind and unit for M (and ensure they obey the three monad laws), then the type M forms a monad, and instances of type M are objects of the monad.
--
Sébastien
Tue, 2011-07-26, 13:57
#23
Re: i think i got it (monads and stuff)
On Mon, Jul 25, 2011 at 11:38 PM, HamsterofDeath <h-star@gmx.de> wrote:
I'd like to compare this to the reality of Monoids (which in my mind is easier to understand). Consider a Monoid definition like this:
Instead with a type class like this:
There is also another issue with the subclass approach. There are more than one Monoid possible for any given T so it makes no sense to pick one of them and implement an "is-a" relationship with it.
Compare
A question for the Monad experts: Is this situation the same for Monads? I.e. for any given functor can we have more than one Monads? Is it correct to talk about _the_ List-monad?
BR,
John
my brain refuses to see any sense in an implementation of a monad trait that does not return an instance of monad in the bind and unit method and accepts an instance of monad in the bind method.
I'd like to compare this to the reality of Monoids (which in my mind is easier to understand). Consider a Monoid definition like this:
trait Monoid[T] {
val id: T
def op(t: T): T
}
With this we could implement a sum like so:
def sum[T<%Monoid[T]](ts:List[T]):T = ts.head op sum(ts.tail)
However the empty case gets tricky because we have no object from which to get idInstead with a type class like this:
class Monoid[T](val id: T, val op: (T, T) => T)
We get an object to handle the empty case
def sum[T](ts: List[T])(implicit m: Monoid[T]): T = ts match {
case Nil => m.id
case t :: ts => m.op(t, sum(ts))
}
There is also another issue with the subclass approach. There are more than one Monoid possible for any given T so it makes no sense to pick one of them and implement an "is-a" relationship with it.
Compare
Monoid[Int](0,_+_)
to Monoid[Int](1,_*_)
.
A question for the Monad experts: Is this situation the same for Monads? I.e. for any given functor can we have more than one Monads? Is it correct to talk about _the_ List-monad?
BR,
John
Tue, 2011-07-26, 14:07
#24
Re: i think i got it (monads and stuff)
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
On 26/07/11 22:53, John Nilsson wrote:
> On Mon, Jul 25, 2011 at 11:38 PM, HamsterofDeath
> wrote:
>
>> my brain refuses to see any sense in an implementation of a monad
>> trait that does not return an instance of monad in the bind and
>> unit method and accepts an instance of monad in the bind method.
>>
>
> I'd like to compare this to the reality of Monoids (which in my
> mind is easier to understand). Consider a Monoid definition like
> this:
>
> trait Monoid[T] { val id: T def op(t: T): T }
>
> With this we could implement a sum like so:
>
> def sum[T<%Monoid[T]](ts:List[T]):T = ts.head op sum(ts.tail)
>
> However the empty case gets tricky because we have no object from
> which to get id
>
> Instead with a type class like this:
>
> class Monoid[T](val id: T, val op: (T, T) => T)
>
> We get an object to handle the empty case
>
> def sum[T](ts: List[T])(implicit m: Monoid[T]): T = ts match { case
> Nil => m.id case t :: ts => m.op(t, sum(ts)) }
>
>
> There is also another issue with the subclass approach. There are
> more than one Monoid possible for any given T so it makes no sense
> to pick one of them and implement an "is-a" relationship with it.
> Compare Monoid[Int](0,_+_) to Monoid[Int](1,_*_).
>
>
> A question for the Monad experts: Is this situation the same for
> Monads? I.e. for any given functor can we have more than one
> Monads? Is it correct to talk about _the_ List-monad?
>
>
> BR, John
>
There is only one Monad for List that satisfies the 3 laws. This is
not true for applicative functors though. We can talk about "the list
monad", but only because it is incidentally unambiguous to do so.
Tue, 2011-07-26, 14:17
#25
Re: i think i got it (monads and stuff)
On Tue, Jul 26, 2011 at 02:51, HamsterofDeath wrote:
>
>> trait Monad[M[_]] {
>> def bind[A, B](ma:M[A])(f:A => M[B]):M[B]
>> def unit[A](a:A):M[A]
>> def fmap[A, B](f:A => B):M[A] => M[B]
>> def ap[A, B](f:M[A => B]):M[A] => M[B]
>> }
>> the less sense it makes.
>
> no, it's not. it returns functions that can convert M[A] into M[B], not
> Monad[A] into Monad[B] - unless you declare M as M <: Monad[_]
It's a typeclass, actually. One could think to write it as:
abstract class Monad[M[_] : Monad] {
def bind[A, B](ma:M[A])(f:A => M[B]):M[B]
def unit[A](a:A):M[A]
def fmap[A, B](f:A => B):M[A] => M[B]
def ap[A, B](f:M[A => B]):M[A] => M[B]
}
But that would be useless and cause a circular reference problem. For example:
scala> implicit object ListMonad extends Monad[List] {
| def bind[A, B](ma: List[A])(f: A => List[B]): List[B] = ma flatMap f
| def unit[A](a: A): List[A] = List(a)
| def fmap[A, B](f: A => B): List[A] => List[B] = (_: List[A]) map f
| def ap[A, B](f: List[A => B]): List[A] => List[B] = (_:
List[A], f).zipped map ((a, g) => g(a)) // I suspect List isn't an
applicative...
| }
:17: error: super constructor cannot be passed a self
reference unless parameter is declared by-name
implicit object ListMonad extends Monad[List] {
^
Tue, 2011-07-26, 14:27
#26
Re: i think i got it (monads and stuff)
On Tue, Jul 26, 2011 at 09:53, John Nilsson wrote:
> On Mon, Jul 25, 2011 at 11:38 PM, HamsterofDeath wrote:
>>
>> my brain refuses to see any sense in an implementation of a monad trait
>> that does not return an instance of monad in the bind and unit method and
>> accepts an instance of monad in the bind method.
>
> I'd like to compare this to the reality of Monoids (which in my mind is
> easier to understand). Consider a Monoid definition like this:
>
> trait Monoid[T] {
> val id: T
> def op(t: T): T
> }
>
> With this we could implement a sum like so:
>
> def sum[T<%Monoid[T]](ts:List[T]):T = ts.head op sum(ts.tail)
def sum[T <% Monoid[T](ts: List[T]): T = if (ts isEmpty) id else
ts.head op sum(ts.tail)
>
> However the empty case gets tricky because we have no object from which to
> get id
>
> Instead with a type class like this:
>
> class Monoid[T](val id: T, val op: (T, T) => T)
>
> We get an object to handle the empty case
>
> def sum[T](ts: List[T])(implicit m: Monoid[T]): T = ts match {
> case Nil => m.id
> case t :: ts => m.op(t, sum(ts))
> }
>
>
> There is also another issue with the subclass approach. There are more than
> one Monoid possible for any given T so it makes no sense to pick one of them
> and implement an "is-a" relationship with it.
> Compare Monoid[Int](0,_+_) to Monoid[Int](1,_*_).
>
>
> A question for the Monad experts: Is this situation the same for Monads?
> I.e. for any given functor can we have more than one Monads? Is it correct
> to talk about _the_ List-monad?
>
>
> BR,
> John
>
Tue, 2011-07-26, 17:37
#27
RE: FW: i think i got it (monads and stuff)
I love replying to myself J
Here’s another complication I just saw in Martin’s talk:
List (1,2,3) map (0 to _) => List[Range]
List (1,2,3) flatMap (0 to _)
Well, it’s not the List Monad anymore, is it? What does Range have to do with List? Just that they share the same ancestry with TraversableLike where flatMap happens to be defined…
So here, the shape of the monad is sadly not List but TraversableLike which brings into play the type hierarchy as well. It is thus puzzling that the result is a List[Int] until you see the signature
def flatMap[B, That](f: A => GenTraversableOnce[B])(implicit bf: CanBuildFrom[Repr, B, That]): That = {
The importance of decoupling the concept from the syntactic representation and providing multiple representations cannot be understated! And more plain OO friendliness would be appreciated by the poor bastards with no advanced programing experience like me… J
BTW here’s the adapter version that actually fully compiles: https://gist.github.com/1107128 there’s clearly a reason why I’m not allowed to write production code at work J
It’s missing another adapter to make it a proper scala collection monad with CanBuildFrom and all that… if someone’s so inclined. Fork it, baby, fork it!
Cheers,
Razie
From: Razvan Cojocaru [mailto:pub@razie.com]
Sent: July-25-11 11:22 PM
To: 'Meredith Gregory'; tmorris@tmorris.net
Cc: scala-user@googlegroups.com
Subject: RE: FW: [scala-user] i think i got it (monads and stuff)
The “container” thing slipped… but it did actually help me I think initially to descope the abstracts.
Indeed, about OO, monads and Java – there’s a lot to be said. The most important I think is the domain modeling aspect. An OO person understands that concepts map to objects and these are usable. Plain old limited UML. But when you say Monad – it is not it! It’s just a reflection of a part of the underlying thing, because everyone says “the List Monad” and that “List is a monad” and then we see the Monad trait and it’s not useful by itself… and then you’re tweaking it even further (now I understand why) so that bind () returns not even a thing but a thing to later give me a thing!!! Ahh, the laziness!
It’s a big impedance mismatch… as an OOpist, I need to “dot something”… I don’t have a “dot something”. When you say “it’s a Monad” well, I expect it to derive from it at some point and actually be one, but it doesn’t. Ahhh!!! J
There’s a bunch of other stuff on top of that, you need to make this pattern work:
- higher functions – I’m lucky to have an extensive C++ background where you could pass methods (well, pointers to)
- Type parametrization – fairly new in Java really… again C++ background helps
- Higher kinds – opa.
- Implicits – again lucky with C++, although different, I have a feel for it
- Duck typing – in the implementation of the for comprehension… opa! This is probably the least OO-friendly here
- Usefulness which is really apparent in the for comprehension and similar syntax, just because chaining flatmaps is so not obvious J
Seriously, there’s a lot of moving parts to this. Once you get past the initial shock and separate the (mathematical) concept, it’s usefulness and its possibly different representations in scala or whathave you and the respective techniques, it’s different and that’s the crossing of the Styx I was talking about.
I don’t want to go down another “OMG, scala is complex” because it’s not, just want to point that the implicit implementation in C++ is somehow more aligned with an OO mindset than the one in scala. I understand the limitations, but still… the impedance mismatch. All these impedance mismatches are like pairs of glasses that add to make the picture that much more distorted and hard to understand.
Greg – as you know, I find your colored braces approach with the shape and roll, very useful.
Cheers,
Razie
From: scala-user@googlegroups.com scala-user [at] googlegroups [dot] com]" rel="nofollow">[mailto:scala-user@googlegroups.com] On Behalf Of Meredith Gregory
Sent: July-25-11 7:36 PM
To: tmorris@tmorris.net
Cc: scala-user@googlegroups.com
Subject: Re: FW: [scala-user] i think i got it (monads and stuff)
Dear Tony,
i agree -- in principle -- that thinking of the functor underlying the monad as a container can be limiting -- precisely because it can later be confusing when we generalize to control. However, what can be shown is that the syntactic view is canonical. For example, thinking of monads as colored braces is canonical and aligns with people's intuitions about XML. So bootstrapping an understanding in this way is provably sound.
Philosophically, it's even more important to understand that every model factors through a syntactic presentation because
- that is the essence of the computational interpretation of monads -- they reify computation
- our only handle on control is via syntax -- we have to manipulate the infinitary objects of computation through (something equivalent to) source code -- that's our only way to grab a computation and treat it as data
Dear Razie,
You raise a good point regarding OO. i observe that at least twice, now, OO has lead the Scala design team down the primrose path. The first is the way the for-comprehensions syntax maps to the underlying interface -- which doesn't make the separation between data structure and API that it ought to. The second is the way inheritance is misused to address the relationship between collection and function. In both cases the failing is actually a failing to take OO principles far enough and make important contextual information into computational entities.
Best wishes,
--greg
On Mon, Jul 25, 2011 at 4:20 PM, Tony Morris <tonymorris@gmail.com> wrote:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
There's nothing too foreign here to anyone coming from Java. There is
higher-order polymorphism and a bit more discipline in the types. The
rest is already familiar. The Monad interface is just that -- an
interface. Interfaces are implemented by various data structures, in
this case, type constructors. They give rise to useful operations as a
result.
Here is one such operation:
// top of my head, may not compile!
def sequence[F[_], A](x: List[F[A]], m: Monad[F]): F[List[A]] =
x match {
case Nil => m.point(Nil)
case h::t => m.bind(hh => m.bind(tt => m.point(hh::tt))(t))(h)
} // can be written a bit neater using foldRight
Here is another:
def filterM[F[_], A](p: A => F[Boolean], x: List[A], m: Monad[F]):
F[List[A]] = error("readers exercise")
Of course you can then do fancy things with implicits and that Monad
argument.
PS: I am very much against calling the type constructor a "container"
for the purposes of teaching.
On 26/07/11 08:58, Razvan Cojocaru wrote:
> I think that people coming from FP to scala see the world
> differently from people coming from OO to scala. Getting the answer
> to this particular question was a very important step for me, I
> think of it as crossing the Styx backwards J and unfortunately,
> have not seen this nicely laid out anywhere so far. Why Monad
> versus ScalaMonad versus just flatmap and how the heck is all this
> useful etc?
>
>
>
> So to fully answer the HoD puzzle below, the Monad used by Tony is
> separate from the actual container F, so that you can use it on
> types you get from some library. I believe that scalaz uses that
> pattern, together with implicit conversions to make these look nice
> on the underlying containers. There be dragons - very advanced
> stuff there, well over my head and/or effort allotted J but I think
> I get the 10kfeet picture.
>
>
>
> So, if you get a container C[_] from somewhere, you write the CM[C]
> monadic implementation for it and an implicit conversion and then
> some magic happens?
>
>
>
> Check this out for a moment:
>
>
>
> https://github.com/scalaz/scalaz/blob/master/core/src/main/scala/scalaz/Bind
>
>
.scala
>
>
>
> if I?m way off, I?m sure Tony will whack me over the head with some
> fmap or something J
>
>
>
> cheers,
>
> Razie
>
>
>
> From: scala-user@googlegroups.com
> [mailto:scala-user@googlegroups.com] On Behalf Of HamsterofDeath
> Sent: July-25-11 5:39 PM To: scala-user@googlegroups.com Subject:
> Re: [scala-user] i think i got it (monads and stuff)
>
>
>
> the longer i look at this trait Monad[M[_]] { def bind[A,
> B](ma:M[A])(f:A => M[B]):M[B] def unit[A](a:A):M[A] def fmap[A,
> B](f:A => B):M[A] => M[B] def ap[A, B](f:M[A => B]):M[A] => M[B] }
> the less sense it makes.
>
> i understand wrapping a:A in m:M[A]. i understand mapping M[A] to
> M[B] simple. i understand if you say "monad = both methods
> together", making a monad a utiliy object, not different from the
> well known *Utils-classes of java. i understand how option works.
> but i cannot make the mental jump to the monad trait. the
> implementation is nothing more than a function composer which i
> simply could do directly or via not-part-of-a-trait utility-methods
> if the logic is more complex. my brain refuses to see any sense in
> an implementation of a monad trait that does not return an instance
> of monad in the bind and unit method and accepts an instance of
> monad in the bind method.
>
>
> Am 25.07.2011 22:37, schrieb Sébastien Bocq:
>
> I mean this is implementation specific.
>
> 2011/7/25 Sébastien Bocq <sebastien.bocq@gmail.com>
>
> I'd like to know other opinions, but I find that avoiding OO makes
> it easier to reason about these abstract concepts in Scala. Here is
> my version of the identity monad:
>
> trait Monad[M[_]] { def bind[A, B](ma:M[A])(f:A => M[B]):M[B] def
> unit[A](a:A):M[A] def fmap[A, B](f:A => B):M[A] => M[B] def ap[A,
> B](f:M[A => B]):M[A] => M[B] }
>
> type Id[A] = A
>
> implicit val mId = new Monad[Id] { def bind[A, B](a:Id[A])(f:A =>
> Id[B]) = f(a) def unit[A](a:A) = a def fmap[A, B](f:A => B) = f def
> ap[A, B](f:Id[A => B]) = f }
>
> (See how identity fmap a function to itself.)
>
> Now you can box the monad inside an object to use it in a
> for-comprehension but this is incidental (I'm wondering if the
> boxing is optimized away by the JVM).
>
> trait MonadTrait[M[_], A] { def flatMap[B](f:A => M[B]):M[B] def
> map[B](f:A => B):M[B] }
>
> implicit def idBox[A](ma:Id[A])(implicit m:Monad[Id]) = new
> MonadTrait[Id, A] { def flatMap[B](f:A => Id[B]) = m.bind(ma)(f)
> def map[B](f:A => B):Id[B] = m.fmap(f)(ma) }
>
> def test(x:Id[Int]) = for { y <- x * x z <- y + y } yield (y + z)
>
> println(test(42))
>
> Have fun!
>
>
>
> 2011/7/25 HamsterofDeath <h-star@gmx.de>
>
> this compiles: trait Monad[F[_]] { def point[A](a: => A): F[A]
>
> def bind[A, B](f: A => F[B]): F[A] => F[B] }
>
> case class Identity[A](a: A)
>
> object Monad { val IdentityMonad: Monad[Identity] = new
> Monad[Identity] { def bind[A, B](f: (A) => Identity[B]) =
> (e:Identity[A]) => f(e.a)
>
> def point[A](a: => A) = Identity(a) } }
>
> val identity = Monad.IdentityMonad.point("hi") val transformer =
> Monad.IdentityMonad.bind((e: String) =>
> Monad.IdentityMonad.point(e.toInt)) val wohoo =
> transformer.apply(identity)
>
>
> Am 24.07.2011 23:10, schrieb Tony Morris:
>> trait Monad[F[_]] { def point[A](a: => A): F[A] def bind[A, B](f:
>> A => F[B]): F[A] => F[B] }
>>
>> case class Identity[A](a: A)
>>
>> object Monad { val IdentityMonad: Monad[Identity] = error("todo")
>> }
>
>
>
>
>
>
- --
Tony Morris
http://tmorris.net/
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/
iEYEARECAAYFAk4t+icACgkQmnpgrYe6r62kKwCglTF6+LFG7KojSNkPmvKE3e5X
y0IAn3TweSrNsrQjK1Wx+XEEy5g2fTaM
=VSNT
-----END PGP SIGNATURE-----
--
L.G. Meredith
Managing Partner
Biosimilarity LLC
7329 39th Ave SW
Seattle, WA 98136
+1 206.650.3740
http://biosimilarity.blogspot.com
Wed, 2011-07-27, 08:37
#28
Re: FW: i think i got it (monads and stuff)
On Tue, Jul 26, 2011 at 6:29 PM, Razvan Cojocaru wrote:
> It’s missing another adapter to make it a proper scala collection monad with
> CanBuildFrom and all that… if someone’s so inclined. Fork it, baby, fork it!
https://github.com/scalaz/scalaz/blob/master/core/src/main/scala/scalaz/...
https://github.com/scalaz/scalaz/blob/master/core/src/main/scala/scalaz/...
-jason
This is a good start! Monads are quite frequently (but not always)
about sequencing operations. One thing I'd encourage though is that
you not ignore the monad laws - with your newfound understanding, they
should be easy to remember.
A really good exercise to deepen your understanding is to implement
the Reader monad. Here's a skeleton that you can fill in the
implementation for, if you like: https://gist.github.com/1037030
On Sun, Jul 24, 2011 at 6:48 AM, HamsterofDeath wrote:
> after reading lots of stuff on monads, i made up my own explanation that
> is incredibly simple and doesn't contain cryptic symbols :)
>
> it goes like this:
> class Wrapper(x:X)
>
> that is a monad. i left out the confusing parts
>
> you use it like this:
>
> instead of
>
> val myMutableThing = ...
> myMutableThing.mutate()
>
> you do
>
> val monad = new Wrapper(myImmutableThing)
> val nextMonad = monad.chainOperation(mutation)
>
> and later:
> lastMonad.result
>
> does that make sense so far? not really? well, it opens a whole new
> world. the monad is a "void-monad" so far, it doesn't do anything. what
> makes it cool is that you can make it "carry something along"
> instead of a changing state, you have a chain of things that describe
> the changes that accumulate along the way.
> like the loggingmonad here:
> http://www.lambdascale.com/2010/12/the-adventures-of-a-java-developer-in...
>
>
>