Why is a Range transformed to a Vector after map operation?

回眸只為那壹抹淺笑 提交于 2019-12-09 16:37:56

问题


Following Scala courses on Coursera, Martin Odersky showed an example code which is:

1 to 5 map ( i => i*i )

And he said the Range gets transformed to a Vector because they share the same interface (IndexedSeq) and the result could not be represented as a Range (it was more clear in its example since he generated a pair which is not representable as a Range).

I'm not sure to understand because I think he said previously that in a for expression the 1st generator will determine the kind of element that will be yielded, and it seems not always true, at least for Range.

And I'm not sure to understand why the output is Vector, because Vector may not be the only other one implementation that can represent the result computed above.

Can someone help me understand this part please?


回答1:


map secretly takes a CanBuildFrom as an implicit argument. Its job is to produce a new collection given the one you've already got (and the type of the contents). Since Range can't contain arbitrary stuff--not even arbitrary integers--there is no CanBuildFrom that produces a Range. The most specific supertype of Range that does have a CanBuildFrom is IndexedSeq. The collection that is actually built by this is a Vector.




回答2:


As I'm sure Martin also explained, for comprehensions correspond to (are translated into) chained invocations of the map and flatMap methods (and foreach if you don't use yield).

The reason why it generally results in a value of the type of the first generator is that map and flatMap generally return the same type as their receiver (map on a List returns a List, etc.).

Now the problem with Ranges is that they cannot represent things that are not regular sequences of integers. As a consequence, the return type of map and flatMap as defined for Range cannot be Range. The next best match is Vector, the prototypical implementation of an indexed sequence.

(If you look at the source code or even the Scala doc page I linked to, you will see that it is a little more complicated that just the return type, but conceptually, that is the reason. Edit: ...and now Rex Kerr just dropped the CanBuildFrom bomb.)




回答3:


Vector is the default implementation for IndexedSeq. The map cannot be represented as a Range since the Range class is designed to contain a series of numbers that can be represented by a start, stop, and step value (similar to range in Python). The API docs specify that it's a special case of IndexSeq.

We can see 1 to 5 map { i => i * i } will get us a container of values (1, 4, 9, 16, 25). We can get a start and stop, but no constant step value.



来源:https://stackoverflow.com/questions/13130458/why-is-a-range-transformed-to-a-vector-after-map-operation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!