将标识函数映射到Scala集合的复杂性?

将标识函数映射到Scala集合的复杂性?,scala,scala-collections,scala-compiler,Scala,Scala Collections,Scala Compiler,当我使用map方法将Scala预定义标识函数应用于集合时,原始集合将原封不动地返回。但是,编译器是否足够聪明,可以简单地将未更改的集合作为O1操作返回?或者标识函数是否仍将应用于原始集合中的每个元素,从而产生一个On操作?测量执行时间似乎表明标识函数处于On状态: 用于测量代码执行时间的函数,从: 测量执行时间似乎表明标识功能已打开: 用于测量代码执行时间的函数,从: 检查情况是否如此非常简单。首先用可能优化过的表单制作一个测试文件,然后使用scalac编译它,无论是否使用-optimize 然

当我使用map方法将Scala预定义标识函数应用于集合时,原始集合将原封不动地返回。但是,编译器是否足够聪明,可以简单地将未更改的集合作为O1操作返回?或者标识函数是否仍将应用于原始集合中的每个元素,从而产生一个On操作?

测量执行时间似乎表明标识函数处于On状态:

用于测量代码执行时间的函数,从:


测量执行时间似乎表明标识功能已打开:

用于测量代码执行时间的函数,从:


检查情况是否如此非常简单。首先用可能优化过的表单制作一个测试文件,然后使用scalac编译它,无论是否使用-optimize

然后,检查javap-c TestMap.class,您可以看到,通过专门化映射到mapSeq、mapList或mapOption,没有任何优化:


更简单地说,这种优化在有副作用的语言中无法很好地扩展。另一方面,在Haskell中,这种事情经常发生。例如,编译器是否应该将l.mapx=>{printlnx;x}优化为l?

检查情况是否如此非常简单。首先用可能优化过的表单制作一个测试文件,然后使用scalac编译它,无论是否使用-optimize

然后,检查javap-c TestMap.class,您可以看到,通过专门化映射到mapSeq、mapList或mapOption,没有任何优化:

更简单地说,这种优化在有副作用的语言中无法很好地扩展。另一方面,在Haskell中,这种事情经常发生。例如,编译器是否应该将l.mapx=>{printlnx;x}优化为l?

Rex Kerr的结论证实了Alec的发现。标识运行时大致与集合大小成比例

val smallC = Vector.tabulate(90)(_*2)
val bigC = Vector.tabulate(900)(_*2)

val th = ichi.bench.Thyme.warmed(verbose = print)
th.pbenchOffWarm("A vs. B")(th.Warm(smallC.map(identity)))(th.Warm(bigC.map(identity)))
雷克斯·克尔的研究证实了亚历克的发现。标识运行时大致与集合大小成比例

val smallC = Vector.tabulate(90)(_*2)
val bigC = Vector.tabulate(900)(_*2)

val th = ichi.bench.Thyme.warmed(verbose = print)
th.pbenchOffWarm("A vs. B")(th.Warm(smallC.map(identity)))(th.Warm(bigC.map(identity)))
当我使用map方法将Scala预定义标识函数应用于集合时,原始集合将原封不动地返回

不,不是。返回内容相同的新集合。构建此新集合通常将启用

但是,编译器是否足够聪明,可以简单地将未更改的集合作为O1操作返回?或者identity函数仍将应用于原始集合中的每个元素,从而生成On操作

为了执行这样的优化,编译器必须确定要应用的函数在扩展上等于标识函数。这个问题称为函数问题,已知是不可判定的。例如,可以使用停止问题来证明这一点

当然,可以优化特定函数Predef.identity,而不仅仅是任何identity函数。但是Scala编译器设计者不喜欢这种一次性的特例优化,这种优化只帮助标准库代码。他们更喜欢对所有代码都有利的一般优化

当我使用map方法将Scala预定义标识函数应用于集合时,原始集合将原封不动地返回

不,不是。返回内容相同的新集合。构建此新集合通常将启用

但是,编译器是否足够聪明,可以简单地将未更改的集合作为O1操作返回?或者identity函数仍将应用于原始集合中的每个元素,从而生成On操作

为了执行这样的优化,编译器必须确定要应用的函数在扩展上等于标识函数。这个问题称为函数问题,已知是不可判定的。例如,可以使用停止问题来证明这一点


当然,可以优化特定函数Predef.identity,而不仅仅是任何identity函数。但是Scala编译器设计者不喜欢这种一次性的特例优化,这种优化只帮助标准库代码。他们更喜欢对所有代码都有利的一般优化。

因此,identity函数确实应用于集合的每个元素?是的,尽管我刚刚意识到我的javap输出在这里是不够的。更新内容:那么,identity函数是否应用于集合的每个元素?是的,尽管我刚刚意识到我的javap输出在这里是不够的。更新内容:好的,从技术上讲,这个问题只要求对Predef.identity执行此操作,而不是对所有扩展上等于它的函数执行此操作,而且这可以非常简单地完成。但是稍微放慢所有地图操作来加速一个非常罕见的案例是不值得的。是的,你是对的。我添加了最后一段并做了澄清。好吧,从技术上讲,这个问题只要求你做这件事
def.identity,并不是所有函数都可以扩展为它,这可以非常简单地完成。但是稍微放慢所有地图操作来加速一个非常罕见的案例是不值得的。是的,你是对的。我添加了最后一段并进行了澄清。
Compiled from "TestMap.scala"
public final class TestMap {
  public static <T extends java/lang/Object> scala.collection.Seq<T> mapSeq(scala.collection.Seq<T>);
    Code:
       0: getstatic     #16                 // Field TestMap$.MODULE$:LTestMap$;
       3: aload_0       
       4: invokevirtual #18                 // Method TestMap$.mapSeq:(Lscala/collection/Seq;)Lscala/collection/Seq;
       7: areturn       

  public static <T extends java/lang/Object> scala.collection.immutable.List<T> mapList(scala.collection.immutable.List<T>);
    Code:
       0: getstatic     #16                 // Field TestMap$.MODULE$:LTestMap$;
       3: aload_0       
       4: invokevirtual #22                 // Method TestMap$.mapList:(Lscala/collection/immutable/List;)Lscala/collection/immutable/List;
       7: areturn       

  public static <T extends java/lang/Object> scala.Option<T> mapOption(scala.Option<T>);
    Code:
       0: getstatic     #16                 // Field TestMap$.MODULE$:LTestMap$;
       3: aload_0       
       4: invokevirtual #26                 // Method TestMap$.mapOption:(Lscala/Option;)Lscala/Option;
       7: areturn  
val smallC = Vector.tabulate(90)(_*2)
val bigC = Vector.tabulate(900)(_*2)

val th = ichi.bench.Thyme.warmed(verbose = print)
th.pbenchOffWarm("A vs. B")(th.Warm(smallC.map(identity)))(th.Warm(bigC.map(identity)))
Benchmark comparison (in 4.694 s): A vs. B
Significantly different (p ~= 0)
  Time ratio:    9.31267   95% CI 9.25599 - 9.36935   (n=20)
    First     1.492 us   95% CI 1.487 us - 1.496 us
    Second    13.89 us   95% CI 13.82 us - 13.96 us