Scala:链接映射是否由编译器优化?

时间:2015-09-18 04:19:33

标签: scala maps compiler-optimization

Scala有一种将集合转换为另一个集合的惊人方式 地图构造。

if (wordsProcessed == numOfPuzzl) {
    printf("\n");
    while ( fgets(myString, 256, pFile) != NULL ){
        if ( sscanf(myString, "%d", &numOfPuzzl) == 1 )
            break;
    }
    wordsProcessed = 0;
}

将返回列表val l = List(1, 2, 3, 4) l.map(_*_)

中元素的方块

我遇到了多个地图链接在一起的各种情况,例如

l

我认为在下面发生的事情等同于以下内容。

val l = List(1, 2, 3, 4)
val res = l.map(_ * _).map(_ + 1).filter(_ < 3)
如果集合太大,

创建val l = List(1, 2, 3, 4) val l1 = l.map(_*_) val l2 = l1.map(_ + 1) val res = l2.filter(_ < 3) l1可能会导致内存问题。 要解决这个问题,Scala编译器是否有任何优化?

l2

一般情况下val l = List(1, 2, 3, 4) val res = l1.map( _*_ + 1).filter(_ < 3) fg是函数

h

可以转换为

val l = List(/*something*/)
val res = l.map(f(_)).map(g(_)).map(h(_))

2 个答案:

答案 0 :(得分:3)

Scala提供Stream,这是一个懒惰的有序集合。

val s = Stream(1, 2, 3, 4)

// note i've changed your sequence of transformations
// a bit, so that it compiles and yields more than one result
val res = s.map(i => i * i).map(_ + 1).filter(_ < 11)

res现在是Stream。尚未执行任何实际评估,未使用与s大小相关的内存块。

如果您打算一次使用res个元素,则无需再进行任何工作。例如,您可以直接在for语句或理解中使用res

for ( elem <- res ) println( s"A value is ${elem}" )

如果您希望resList,则可以在转换序列结束时调用.toList。而不是上述,使用

val res = s.map(i => i * i).map(_ + 1).filter(_ < 11).toList

s只会在创建新List时遍历一次。

答案 1 :(得分:0)

不,因为这需要编译器知道map的语义并且特别对待实现它的标准库类(因为没有人阻止你编写一个没有这个的类) 。有一个research proposal可能最终会实现这个......最终。

还有Scala-Blitz优化了一些收集操作,但融合和砍伐森林被列为this presentation中的未来工作,我认为它们尚未实施。

正如Steve Waldman的回答所说,使用Stream(或者,更好的是Iterator)可以提供帮助,但它不会完全消除中间集合。