Map as iteration vs monad function application

79 views
Skip to first unread message

Jim Newton

unread,
Sep 22, 2016, 6:15:52 AM9/22/16
to scala-user
I'm trying to read through the red book: FPIS (chiusano,bjarndon). Some of the concepts sre difficult to grasp.

Can someone explain the connection between accessing the value in a monad, and iteration? The author dances around this but I have had dreams thinking about it.

I can't completely formulate the question as I'm confused. But sometimes it seems a monad is just a compilable wrapper around a value such as future or option, and map calls a function on that value. But in the case of a list map performs an iteration.

I've always thought of map and flatMap as iteration functions because they "map over a sequence". But that no longer seems to be the case.

Jasper-M

unread,
Sep 22, 2016, 7:03:05 AM9/22/16
to scala-user
Map basically just applies a function to the contents of a container and returns a new container containing the result. Properties of that content, like amount of values or when those values become available, don't matter.

Op donderdag 22 september 2016 12:15:52 UTC+2 schreef Jim Newton:

Tushar Tyagi

unread,
Sep 22, 2016, 11:00:44 AM9/22/16
to scala...@googlegroups.com
Don't think of List as an iteration of values but just a container of
values. It can have any type of values, as long as the values have the
same (super)type.

`map` takes in a container and returns a new container with the given
function applied to each value in the container. What will happen if
the container has only a single value or no value? Thinking broadly,
this is just what an `Option` is.
It has only a single value (Some[A]) or no value (None) at all and
mapping a function (f :: A -> B) will give Some[B] or None for the
values Some[A] or None.

Thinking yet more broadly, it turns out that once you understand that
map can transform the contents of one collection into different values
of the same collection (mapping a List turns it into a different List,
but not to an Option, and vice versa), we can use these with Monads as
well (because Monads are containers as well which follow some laws --
List is a Monad as well :)

I would also suggest to use multiple sources (books and blogs) to
understand what Monads are, and try to reimplement the Monad operations
(bind) using `map`.

--
Tushar Tyagi
t...@fastmail.com
> --
> You received this message because you are subscribed to the Google Groups
> "scala-user" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to scala-user+...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

PUB Razvan Cojocaru

unread,
Sep 26, 2016, 4:13:51 AM9/26/16
to Jim Newton, scala-user
Without going to category theory, there’s some simple ways to think about this…

The monad’s interface is essentially just two operations: unit and bind… neither of which lets you take things out of it. An iteration, an externalized loop, almost by definition, does take things out of it and allows you to ignore completely where they came from… i.e. the shape of the monad… in fact you give up the most important properties of the monad right there.

Do you think that, with iteration, you are in fact braking the container’s opacity?

Here’s an example I had:

Let’s have a quick random example: I could have my own functor, working on lists, which keeps the elements sorted. If I apply a random function to it, the result has to be also sorted. You can see the problem? my functor will keep it sorted while an externalized loop may or may not keep it sorted, depending on the programmer.

MySortedList (1,2,3) map (rand(_)) will always be sorted, while List (1,2,3) map (rand(_)) is not…


Try not to think of Monads as just containers, but as transformations.

Here’s a trick… you may be used to the scala typical signature, giving you values back:


F.map[B] (f : A => B) : F[B]

But try to think of it in terms of the “theoretical” signature, which does not give us a value, but just a higher level transformation:

map[B] (f : A => B) : F[A] => F[B]

But it’s true: read as much as you can on monads, to understand this abstract fuzzy beast.

This was an intro I wrote a while ago:


cheers,
Razie

p.s. It will help when you realize that 

for (e <- List(1,2,3)) yield e+4

is not an actual iteration. Scala’s “for” is not an iteration, but another trick to simply call map :

for (e <- List(1,2,3)) yield e+4       ===     List(1,2,3).map(_ +4)

Now you can perhaps understand the difference...

PUB Razvan Cojocaru

unread,
Sep 26, 2016, 1:08:16 PM9/26/16
to Jim Newton, scala-user
Sorry, you’re right, I’m lazy: that should’ve been (incorrect syntax anyways):

F[A].map[B] (f : A => B) : F[B]

It was meant to show it as a member, as in

class F[A] {
  def map[B]  (f : A => B) : F[B]
}

---

The functor is the first step in comprehending monads, for me - it lifts a simple function f : A => B into something higher level, fmap:  F[A] => F[B]

Here’s my conceptual steps…

I have a function from A to B

f:A=>B

I have a weird Functor let’s call it F and it can “lift” a given function f to work on the entire set:

F.fmap(f) will take a function f mapping elements of A into elements of B and return a contraption that will turn an entire set F[A] into a F[B], the signature of the contraption being F[A] => F[B]

Hence the signature of the contraption generator being:

// defined outside of F
object FFunctor {
   def map[B]  (f : A => B) : F[A] => F[B]
}

OR, if defined as a member of F

class F {
  def map[B]  (f : A => B) : F[B]
}

Notice the difference… the second one, since it’s a member of a F[A] already, it will return the F[B].

// version 1
val x : F[A] = new F(a1, a2)
val contraption : F[A] => F[B] = FFunctor.map (f)
val y : F[B] = contraption (x)

// version 2
val x : F[A] = new F(a1, a2)
val y : F[B] = x.map (f)

Now instead of F think List or HashMap or Option… they’re all Functors (i.e. contraptions).

So again:

I have a function:

f : A => B

and a Functor F will lift that to work on weird things like F[_] the resulting thing will be a functor:

map : F[A] => F[B].

for instance

def f (a:String) : Int = a.toInt

Now let’s use a strange functor called List:

val listB : List[Int] = List[String](“1”, “2”).map(f)   // == List(1,2)

Note that this was the member version of map


cheers,
raz

p.s. does that make any more sense or did it make it all even more confusing?



On Sep 26, 2016, at 12:21 PM, Jim Newton <jimka...@gmail.com> wrote:

Thanks, that helps somewhat. But I don't understand what a functor is. It sounds like a parameterized function which only exists at compiled time and not at runtime, and thus is not first class.

And also, when you say F.map[B] (f : A => B) : F[B], why is there no "A," inside the first brackets? What is special about B which is not special about A in F.map[B] (f : A => B) : F[B] ?

Reply all
Reply to author
Forward
0 new messages