Comprehension comprehension...

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

Comprehension comprehension...

Peter Wolf
Hello and Happy Holidays!

I was teaching some new developers the Joy Of Comprehension

I showed them that this yields a List

   for { x <- List(1,2,3); y <- List(1,2,3) } yield x+y 

and this yields a Future

  for { x <- Future(1); y <- Future(1) } yield x+y 

Then I asked them what type this would yield

  for { x <- 1 to 3; y <- 1 to 3 } yield x+y

and the answer was...

  res3: scala.collection.immutable.IndexedSeq[Int] = Vector(2, 3, 4, 3, 4, 5, 4, 5, 6)

Huh?  That not what I thought should happen...  I expected a range, or a compile error

I thought perhaps Vector extended Range, but this does not compile

  def foo(a: Range, b: Range): Range = for { x <- a; y <- b } yield x+y

I thought the whole point of Monads and for comprehension is that the type does not change.

Thoughts?

P

--
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 [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Comprehension comprehension...

Patrick Roemer-2
Responding to Peter Wolf:

> Then I asked them what type this would yield
>
>   for { x <- 1 to 3; y <- 1 to 3 } yield x+y
>
> and the answer was...
>
>   res3: scala.collection.immutable.IndexedSeq[Int] = Vector(2, 3, 4, 3, 4,
> 5, 4, 5, 6)
>
> Huh?  That not what I thought should happen...  I expected a range, or a
> compile error

How could it be a Range? What would start/end/step be for the result in
your example? And what if you replace "x+y" with "(x+y).toString"?

> I thought perhaps Vector extended Range, but this does not compile
>
>   def foo(a: Range, b: Range): Range = for { x <- a; y <- b } yield x+y
>
> I thought the whole point of Monads and for comprehension is that the type
> does not change.

Range itself cannot be "monadic", since its element type is fixed - it's
not a type constructor of form M[A].

The "monadic" super type here basically is Traversable. But the Scala
collection API works hard to give you a closer matching type, thus you
end up with IndexedSeq, and the concrete instance happens to be a Vector.

Best regards,
Patrick


--
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 [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Comprehension comprehension...

Peter Wolf
Cool.  

With a little thought, I got that Range could not be a Monad.  I did not understand how the compiler finds a common matching type and does comprehension there.

Here is another example

val x = for { x <- 1 to 2; y <- Set(1) } yield x+y
Vector(2, 3)


On Fri, Dec 23, 2016 at 3:33 PM, Patrick Roemer <[hidden email]> wrote:
Responding to Peter Wolf:
> Then I asked them what type this would yield
>
>   for { x <- 1 to 3; y <- 1 to 3 } yield x+y
>
> and the answer was...
>
>   res3: scala.collection.immutable.IndexedSeq[Int] = Vector(2, 3, 4, 3, 4,
> 5, 4, 5, 6)
>
> Huh?  That not what I thought should happen...  I expected a range, or a
> compile error

How could it be a Range? What would start/end/step be for the result in
your example? And what if you replace "x+y" with "(x+y).toString"?

> I thought perhaps Vector extended Range, but this does not compile
>
>   def foo(a: Range, b: Range): Range = for { x <- a; y <- b } yield x+y
>
> I thought the whole point of Monads and for comprehension is that the type
> does not change.

Range itself cannot be "monadic", since its element type is fixed - it's
not a type constructor of form M[A].

The "monadic" super type here basically is Traversable. But the Scala
collection API works hard to give you a closer matching type, thus you
end up with IndexedSeq, and the concrete instance happens to be a Vector.

Best regards,
Patrick


--
You received this message because you are subscribed to a topic in the Google Groups "scala-user" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/scala-user/WH49O9DGf44/unsubscribe.
To unsubscribe from this group and all its topics, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.

--
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 [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Comprehension comprehension...

Seth Tisue-3
You can demonstrate this with less code, so e.g.

scala> (1 to 3).map(_.toString)
res0: scala.collection.immutable.IndexedSeq[String] = Vector(1, 2, 3)

Recall that for comprehensions are just sugar for calls to map, flatMap, and withFilter.

--
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 [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Comprehension comprehension...

Patrick Roemer-2
In reply to this post by Peter Wolf
Responding to Peter Wolf:
> With a little thought, I got that Range could not be a Monad.  I did not
> understand how the compiler finds a common matching type and does
> comprehension there.

You can explore this in your IDE if you desugar.

val x = (1 to 3).flatMap(x => (1 to 3).map(y => x + y))

IDEA shows that map/flatMap is resolved to TraversableLike, which
returns an abstract That from the CanBuildFrom dance. The type hover on
x shows it's an IndexedSeq[Int]. And "Explain Scala code" shows that the
implicit argument to map/flatMap is IndexedSeq.canBuildFrom, indeed.

> val x = for { x <- 1 to 2; y <- Set(1) } yield x+y
>
> Vector(2, 3)

val y = for { y <- Set(1); x <- 1 to 2 } yield x+y
Set(2, 3)

:)

Best regards,
Patrick


--
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 [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Comprehension comprehension...

som-snytt

I recently said:

https://gitter.im/scala/contributors?at=585cbe64c02c1a3959a25260

to contrast


scala> ('a' to 'e').slice(1,3) res1: scala.collection.immutable.IndexedSeq[Char] = Vector(b, c) scala> ('a' to 'e').drop(1).take(2) res2: scala.collection.immutable.NumericRange[Char] = NumericRange b to c

and I said scaladoc promises a range here:

scala> ('a' to 'e').patch(1, 'x' to 'z', 2)
res6: scala.collection.immutable.IndexedSeq[Char] = Vector(a, x, y, z, d, e)

So promises and expectations are broken. It would be nice if user could find out when or why.

Also, our family nickname in the old country was Roemer, and my dog Roemer passed two years ago Christmas, so it's always a little jolt to see "Roemer". And the other dog was Padraig, Irish for Patrick. So I think I will go sing Auld Lang Syne now.

On Friday, December 23, 2016 at 1:55:46 PM UTC-8, Patrick Roemer wrote:
Responding to Peter Wolf:
> With a little thought, I got that Range could not be a Monad.  I did not
> understand how the compiler finds a common matching type and does
> comprehension there.

You can explore this in your IDE if you desugar.

val x = (1 to 3).flatMap(x => (1 to 3).map(y => x + y))

IDEA shows that map/flatMap is resolved to TraversableLike, which
returns an abstract That from the CanBuildFrom dance. The type hover on
x shows it's an IndexedSeq[Int]. And "Explain Scala code" shows that the
implicit argument to map/flatMap is IndexedSeq.canBuildFrom, indeed.

> val x = for { x <- 1 to 2; y <- Set(1) } yield x+y
>
> Vector(2, 3)

val y = for { y <- Set(1); x <- 1 to 2 } yield x+y
Set(2, 3)

:)

Best regards,
Patrick


--
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 [hidden email].
For more options, visit https://groups.google.com/d/optout.