セカイノカタチ

世界のカタチを探求するブログ。関数型言語に興味があり、HaskellやScalaを勉強中。最近はカメラの話題も多め

Scalaのfor文を掘ってみる

なんか、よく解らないくなったので書き捨て気味。

Scalaのfor文に謎の制限があった気がしたので調査してみた。

for{
	x<-List(1)
	x<-List(x)
	x<-List(x)
	x<-List(x)
	x<-List(x)
	x<-List(x)
	x<-List(x)
	x<-List(x)
	x<-List(x)
	x<-List(x)
	x<-List(x)
	x<-List(x)
	x<-List(x)
	x<-List(x)
	x<-List(x)
	x<-List(x)
	x<-List(x)
	x<-List(x)
	x<-List(x)
	x<-List(x)
	x<-List(x)
	x<-List(x)
	x<-List(x)
	x<-List(x)
	x<-List(x)
	x<-List(x)
	x<-List(x)
	x<-List(x)
	x<-List(x)
	x<-List(x)
	x<-List(x)
	x<-List(x)
	x<-List(x)
}yield x

こんな感じのコードを書いてみると、エラーになったはず。

res0: List[Int] = List(1)

あれ?余裕だった。こんなはずじゃ・・・

for{
x<-List(1)
x<-List(2)
x<-List(3)
x<-List(4)
/*...省略...*/
x<-List(80)
}yield x

That entry seems to have slain the compiler.  Shall I replay
your session? I can re-run each line except the last one.
[y/n]
Abandoning crashed session.

お。何やらエラーが出た。
REPLだと、エラーがスクロールアウトしてしまうので、コンパイルしてみる。

object ForTest {
  def main(args: Array[String]): Unit = {
    val res = for{
      x<-List(1)
      x<-List(2)
      x<-List(3)
      x<-List(4)
      /*...省略...*/
      x<-List(80)
    }yield x
    print(res)
  }
}

エラーメッセージをリダイレクトしてみてみると。

error: java.lang.StackOverflowError
	at scala.tools.nsc.symtab.Symbols$Symbol.ownerChain(Symbols.scala:611)
	at scala.tools.nsc.symtab.Symbols$Symbol.ownerChain(Symbols.scala:611)
	at scala.tools.nsc.symtab.Symbols$Symbol.ownerChain(Symbols.scala:611)
...省略...

何やらスタックオーバーフローのようだ。
限界を探る。とりあえず、50段でどうだ。

object ForTest {
  def main(args: Array[String]): Unit = {
    val res = for{
      x<-List(1)
      x<-List(2)
      x<-List(3)
      x<-List(4)
      /*...省略...*/
      x<-List(50)
    }yield x
    print(res)
  }
}

あっさりコンパイル通る。ふむ。(´・ω・`)





(  ゜Д ゜)

なんか、フォルダがすごいことになってる。

for.scala
ForTest$$anonfun$1$$anonfun$apply$2$$anonfun$apply$3$$anonfun$$$$$2ba3c985645ec38325c378bf7e92d5f4$$$$apply$37$$anonfun$apply$38$$anonfun$apply$39$$anonfun$apply$40$$anonfun$apply$41$$anonfun$apply$42$$anonfun$apply$43$$anonfun$apply$44.class
ForTest$$anonfun$1$$anonfun$apply$2$$anonfun$apply$3$$anonfun$$$$$2ba3c985645ec38325c378bf7e92d5f4$$$$apply$37$$anonfun$apply$38$$anonfun$apply$39$$anonfun$apply$40$$anonfun$apply$41$$anonfun$apply$42$$anonfun$apply$43.class
ForTest$$anonfun$1$$anonfun$apply$2$$anonfun$apply$3$$anonfun$$$$$2ba3c985645ec38325c378bf7e92d5f4$$$$apply$37$$anonfun$apply$38$$anonfun$apply$39$$anonfun$apply$40$$anonfun$apply$41$$anonfun$apply$42.class
ForTest$$anonfun$1$$anonfun$apply$2$$anonfun$apply$3$$anonfun$$$$$2ba3c985645ec38325c378bf7e92d5f4$$$$apply$37$$anonfun$apply$38$$anonfun$apply$39$$anonfun$apply$40$$anonfun$apply$41.class
ForTest$$anonfun$1$$anonfun$apply$2$$anonfun$apply$3$$anonfun$$$$$2ba3c985645ec38325c378bf7e92d5f4$$$$apply$37$$anonfun$apply$38$$anonfun$apply$39$$anonfun$apply$40.class
ForTest$$anonfun$1$$anonfun$apply$2$$anonfun$apply$3$$anonfun$$$$$3f4b974217354c913b39e68ff8b2b6bc$$$$$apply$47$$anonfun$apply$48$$anonfun$apply$49$$anonfun$apply$1.class
ForTest$$anonfun$1$$anonfun$apply$2$$anonfun$apply$3$$anonfun$$$$$91e13cecb8c4b0155330a013f9c28a9a$$$$apply$22$$anonfun$apply$23$$anonfun$apply$24$$anonfun$apply$25$$anonfun$apply$26$$anonfun$apply$27$$anonfun$apply$28$$anonfun$apply$29.class
ForTest$$anonfun$1$$anonfun$apply$2$$anonfun$apply$3$$anonfun$$$$$91e13cecb8c4b0155330a013f9c28a9a$$$$apply$22$$anonfun$apply$23$$anonfun$apply$24$$anonfun$apply$25$$anonfun$apply$26$$anonfun$apply$27$$anonfun$apply$28.class
ForTest$$anonfun$1$$anonfun$apply$2$$anonfun$apply$3$$anonfun$$$$$91e13cecb8c4b0155330a013f9c28a9a$$$$apply$22$$anonfun$apply$23$$anonfun$apply$24$$anonfun$apply$25$$anonfun$apply$26$$anonfun$apply$27.class
ForTest$$anonfun$1$$anonfun$apply$2$$anonfun$apply$3$$anonfun$$$$$91e13cecb8c4b0155330a013f9c28a9a$$$$apply$22$$anonfun$apply$23$$anonfun$apply$24$$anonfun$apply$25$$anonfun$apply$26.class
ForTest$$anonfun$1$$anonfun$apply$2$$anonfun$apply$3$$anonfun$$$$$91e13cecb8c4b0155330a013f9c28a9a$$$$apply$22$$anonfun$apply$23$$anonfun$apply$24$$anonfun$apply$25.class
ForTest$$anonfun$1$$anonfun$apply$2$$anonfun$apply$3$$anonfun$$$$$9995e2ab6ae69e214fd9c05d51f994af$$$$apply$32$$anonfun$apply$33$$anonfun$apply$34$$anonfun$apply$35$$anonfun$apply$36$$anonfun$apply$37$$anonfun$apply$38$$anonfun$apply$39.class
ForTest$$anonfun$1$$anonfun$apply$2$$anonfun$apply$3$$anonfun$$$$$9995e2ab6ae69e214fd9c05d51f994af$$$$apply$32$$anonfun$apply$33$$anonfun$apply$34$$anonfun$apply$35$$anonfun$apply$36$$anonfun$apply$37$$anonfun$apply$38.class
ForTest$$anonfun$1$$anonfun$apply$2$$anonfun$apply$3$$anonfun$$$$$9995e2ab6ae69e214fd9c05d51f994af$$$$apply$32$$anonfun$apply$33$$anonfun$apply$34$$anonfun$apply$35$$anonfun$apply$36$$anonfun$apply$37.class
ForTest$$anonfun$1$$anonfun$apply$2$$anonfun$apply$3$$anonfun$$$$$9995e2ab6ae69e214fd9c05d51f994af$$$$apply$32$$anonfun$apply$33$$anonfun$apply$34$$anonfun$apply$35$$anonfun$apply$36.class
ForTest$$anonfun$1$$anonfun$apply$2$$anonfun$apply$3$$anonfun$$$$$9995e2ab6ae69e214fd9c05d51f994af$$$$apply$32$$anonfun$apply$33$$anonfun$apply$34$$anonfun$apply$35.class
ForTest$$anonfun$1$$anonfun$apply$2$$anonfun$apply$3$$anonfun$$$$$c6bb6e876993f62e2f410c3d58526$$$$apply$27$$anonfun$apply$28$$anonfun$apply$29$$anonfun$apply$30$$anonfun$apply$31$$anonfun$apply$32$$anonfun$apply$33$$anonfun$apply$34.class
ForTest$$anonfun$1$$anonfun$apply$2$$anonfun$apply$3$$anonfun$$$$$c6bb6e876993f62e2f410c3d58526$$$$apply$27$$anonfun$apply$28$$anonfun$apply$29$$anonfun$apply$30$$anonfun$apply$31$$anonfun$apply$32$$anonfun$apply$33.class
ForTest$$anonfun$1$$anonfun$apply$2$$anonfun$apply$3$$anonfun$$$$$c6bb6e876993f62e2f410c3d58526$$$$apply$27$$anonfun$apply$28$$anonfun$apply$29$$anonfun$apply$30$$anonfun$apply$31$$anonfun$apply$32.class
ForTest$$anonfun$1$$anonfun$apply$2$$anonfun$apply$3$$anonfun$$$$$c6bb6e876993f62e2f410c3d58526$$$$apply$27$$anonfun$apply$28$$anonfun$apply$29$$anonfun$apply$30$$anonfun$apply$31.class
ForTest$$anonfun$1$$anonfun$apply$2$$anonfun$apply$3$$anonfun$$$$$c6bb6e876993f62e2f410c3d58526$$$$apply$27$$anonfun$apply$28$$anonfun$apply$29$$anonfun$apply$30.class
ForTest$$anonfun$1$$anonfun$apply$2$$anonfun$apply$3$$anonfun$$$$$e53f4f99c30ac7a10a09f551d71578c$$$$apply$12$$anonfun$apply$13$$anonfun$apply$14$$anonfun$apply$15$$anonfun$apply$16$$anonfun$apply$17$$anonfun$apply$18$$anonfun$apply$19.class
ForTest$$anonfun$1$$anonfun$apply$2$$anonfun$apply$3$$anonfun$$$$$e53f4f99c30ac7a10a09f551d71578c$$$$apply$12$$anonfun$apply$13$$anonfun$apply$14$$anonfun$apply$15$$anonfun$apply$16$$anonfun$apply$17$$anonfun$apply$18.class
ForTest$$anonfun$1$$anonfun$apply$2$$anonfun$apply$3$$anonfun$$$$$e53f4f99c30ac7a10a09f551d71578c$$$$apply$12$$anonfun$apply$13$$anonfun$apply$14$$anonfun$apply$15$$anonfun$apply$16$$anonfun$apply$17.class
ForTest$$anonfun$1$$anonfun$apply$2$$anonfun$apply$3$$anonfun$$$$$e53f4f99c30ac7a10a09f551d71578c$$$$apply$12$$anonfun$apply$13$$anonfun$apply$14$$anonfun$apply$15$$anonfun$apply$16.class
ForTest$$anonfun$1$$anonfun$apply$2$$anonfun$apply$3$$anonfun$$$$$e53f4f99c30ac7a10a09f551d71578c$$$$apply$12$$anonfun$apply$13$$anonfun$apply$14$$anonfun$apply$15.class
ForTest$$anonfun$1$$anonfun$apply$2$$anonfun$apply$3$$anonfun$$$$$f0755ad498a7139e63eab85543dc6e$$$$apply$17$$anonfun$apply$18$$anonfun$apply$19$$anonfun$apply$20$$anonfun$apply$21$$anonfun$apply$22$$anonfun$apply$23$$anonfun$apply$24.class
ForTest$$anonfun$1$$anonfun$apply$2$$anonfun$apply$3$$anonfun$$$$$f0755ad498a7139e63eab85543dc6e$$$$apply$17$$anonfun$apply$18$$anonfun$apply$19$$anonfun$apply$20$$anonfun$apply$21$$anonfun$apply$22$$anonfun$apply$23.class
ForTest$$anonfun$1$$anonfun$apply$2$$anonfun$apply$3$$anonfun$$$$$f0755ad498a7139e63eab85543dc6e$$$$apply$17$$anonfun$apply$18$$anonfun$apply$19$$anonfun$apply$20$$anonfun$apply$21$$anonfun$apply$22.class
ForTest$$anonfun$1$$anonfun$apply$2$$anonfun$apply$3$$anonfun$$$$$f0755ad498a7139e63eab85543dc6e$$$$apply$17$$anonfun$apply$18$$anonfun$apply$19$$anonfun$apply$20$$anonfun$apply$21.class
ForTest$$anonfun$1$$anonfun$apply$2$$anonfun$apply$3$$anonfun$$$$$f0755ad498a7139e63eab85543dc6e$$$$apply$17$$anonfun$apply$18$$anonfun$apply$19$$anonfun$apply$20.class
ForTest$$anonfun$1$$anonfun$apply$2$$anonfun$apply$3$$anonfun$$$$$fbc7d1b81196c14bfe749fcb407d9887$$$$apply$42$$anonfun$apply$43$$anonfun$apply$44$$anonfun$apply$45$$anonfun$apply$46$$anonfun$apply$47$$anonfun$apply$48$$anonfun$apply$49.class
ForTest$$anonfun$1$$anonfun$apply$2$$anonfun$apply$3$$anonfun$$$$$fbc7d1b81196c14bfe749fcb407d9887$$$$apply$42$$anonfun$apply$43$$anonfun$apply$44$$anonfun$apply$45$$anonfun$apply$46$$anonfun$apply$47$$anonfun$apply$48.class
ForTest$$anonfun$1$$anonfun$apply$2$$anonfun$apply$3$$anonfun$$$$$fbc7d1b81196c14bfe749fcb407d9887$$$$apply$42$$anonfun$apply$43$$anonfun$apply$44$$anonfun$apply$45$$anonfun$apply$46$$anonfun$apply$47.class
ForTest$$anonfun$1$$anonfun$apply$2$$anonfun$apply$3$$anonfun$$$$$fbc7d1b81196c14bfe749fcb407d9887$$$$apply$42$$anonfun$apply$43$$anonfun$apply$44$$anonfun$apply$45$$anonfun$apply$46.class
ForTest$$anonfun$1$$anonfun$apply$2$$anonfun$apply$3$$anonfun$$$$$fbc7d1b81196c14bfe749fcb407d9887$$$$apply$42$$anonfun$apply$43$$anonfun$apply$44$$anonfun$apply$45.class
ForTest$$anonfun$1$$anonfun$apply$2$$anonfun$apply$3$$anonfun$apply$4$$anonfun$apply$5$$anonfun$apply$6$$anonfun$apply$7$$anonfun$apply$8$$anonfun$apply$9$$anonfun$apply$10$$anonfun$apply$11$$anonfun$apply$12$$anonfun$apply$13$$anonfun$apply$14.class
ForTest$$anonfun$1$$anonfun$apply$2$$anonfun$apply$3$$anonfun$apply$4$$anonfun$apply$5$$anonfun$apply$6$$anonfun$apply$7$$anonfun$apply$8$$anonfun$apply$9$$anonfun$apply$10$$anonfun$apply$11$$anonfun$apply$12$$anonfun$apply$13.class
ForTest$$anonfun$1$$anonfun$apply$2$$anonfun$apply$3$$anonfun$apply$4$$anonfun$apply$5$$anonfun$apply$6$$anonfun$apply$7$$anonfun$apply$8$$anonfun$apply$9$$anonfun$apply$10$$anonfun$apply$11$$anonfun$apply$12.class
ForTest$$anonfun$1$$anonfun$apply$2$$anonfun$apply$3$$anonfun$apply$4$$anonfun$apply$5$$anonfun$apply$6$$anonfun$apply$7$$anonfun$apply$8$$anonfun$apply$9$$anonfun$apply$10$$anonfun$apply$11.class
ForTest$$anonfun$1$$anonfun$apply$2$$anonfun$apply$3$$anonfun$apply$4$$anonfun$apply$5$$anonfun$apply$6$$anonfun$apply$7$$anonfun$apply$8$$anonfun$apply$9$$anonfun$apply$10.class
ForTest$$anonfun$1$$anonfun$apply$2$$anonfun$apply$3$$anonfun$apply$4$$anonfun$apply$5$$anonfun$apply$6$$anonfun$apply$7$$anonfun$apply$8$$anonfun$apply$9.class
ForTest$$anonfun$1$$anonfun$apply$2$$anonfun$apply$3$$anonfun$apply$4$$anonfun$apply$5$$anonfun$apply$6$$anonfun$apply$7$$anonfun$apply$8.class
ForTest$$anonfun$1$$anonfun$apply$2$$anonfun$apply$3$$anonfun$apply$4$$anonfun$apply$5$$anonfun$apply$6$$anonfun$apply$7.class
ForTest$$anonfun$1$$anonfun$apply$2$$anonfun$apply$3$$anonfun$apply$4$$anonfun$apply$5$$anonfun$apply$6.class
ForTest$$anonfun$1$$anonfun$apply$2$$anonfun$apply$3$$anonfun$apply$4$$anonfun$apply$5.class
ForTest$$anonfun$1$$anonfun$apply$2$$anonfun$apply$3$$anonfun$apply$4.class
ForTest$$anonfun$1$$anonfun$apply$2$$anonfun$apply$3.class
ForTest$$anonfun$1$$anonfun$apply$2.class
ForTest$$anonfun$1.class
ForTest$.class
ForTest.class

何が起きてる!?!?!?

ので、とりあえず最少構成っぽいコードを書く。

object ForTest {
  def main(args: Array[String]): Unit = {
    val list_x = List(1,2,3)
    val list_y = List(4,5,6)
    val res = for{
      x<-list_x
      y<-list_y
    }yield x + y
    print(res)
  }
}

コンパイルしてみる。
なんか、少しだけファイルができる。

ForTest$$anonfun$1$$anonfun$apply$1.class
ForTest$$anonfun$1.class
ForTest$.class
ForTest.class

コンパイル
ForTest.class

import scala.reflect.ScalaSignature;

@ScalaSignature(bytes="\006\0015:Q!\001\002\t\006\025\tqAR8s)\026\034HOC\001\004\003\035aT-\0349usz\032\001\001\005\002\007\0175\t!AB\003\t\005!\025\021BA\004G_J$Vm\035;\024\007\035Q!\003\005\002\f!5\tAB\003\002\016\035\005!A.\0318h\025\005y\021\001\0026bm\006L!!\005\007\003\r=\023'.Z2u!\t\031b#D\001\025\025\005)\022!B:dC2\f\027BA\f\025\005-\0316-\0317b\037\nTWm\031;\t\013e9A\021\001\016\002\rqJg.\033;?)\005)\001\"\002\017\b\t\003i\022\001B7bS:$\"AH\021\021\005My\022B\001\021\025\005\021)f.\033;\t\013\tZ\002\031A\022\002\t\005\024xm\035\t\004'\0212\023BA\023\025\005\025\t%O]1z!\t9#F\004\002\024Q%\021\021\006F\001\007!J,G-\0324\n\005-b#AB*ue&twM\003\002*)\001")
public final class ForTest
{
  public static final void main(String[] paramArrayOfString)
  {
    ForTest..MODULE$.main(paramArrayOfString);
  }
}

ForTest$.class

import scala.Predef.;
import scala.ScalaObject;
import scala.collection.TraversableLike;
import scala.collection.immutable.List;
import scala.collection.immutable.List.;

public final class ForTest$
  implements ScalaObject
{
  public static final  MODULE$;

  static
  {
    new ();
  }

  public void main(String[] args)
  {
    List list_x = List..MODULE$.apply(Predef..MODULE$.wrapIntArray(new int[] { 1, 2, 3 }));
    List list_y$1 = List..MODULE$.apply(Predef..MODULE$.wrapIntArray(new int[] { 4, 5, 6 }));
    List res = 
      (List)list_x.flatMap(new ForTest..anonfun.1(list_y$1), List..MODULE$.canBuildFrom());

    Predef..MODULE$.print(res);
  }

  private ForTest$()
  {
    MODULE$ = this;
  }
}

ForTest$$anonfun$1.class

import scala.Serializable;
import scala.runtime.AbstractFunction1.mcII.sp;

public final class ForTest$$anonfun$1$$anonfun$apply$1 extends AbstractFunction1.mcII.sp
  implements Serializable
{
  public static final long serialVersionUID = 0L;
  private final int x$1;

  public final int apply(int y)
  {
    return apply$mcII$sp(y); } 
  public int apply$mcII$sp(int v1) { return this.x$1 + v1;
  }
}

ForTest$$anonfun$1$$anonfun$apply$1.class

class 
{
}

とりあえず、うわさ通りflatMapに展開されているということは、解った。あと、yield処理は、apply$mcII$sp()に展開されている。
Scalaコンパイラが、forのシンタックスシュガーを自動的に内部クラスに展開するらしいことは、解った。そんで、ネストが深くなると、クラスの定義がドエライことになってコンパイラがスタックオーバーフローすることも解ったような気がする。
この感じだと、forが何重までネストできるかは、環境依存っぽいな。あと、23〜24段でエラーになっていた気がしたのは、32bitのWindows XP環境だったからかな?
今回のコードを2.8.0.final, 2.8.2.final, 2.9.0.final, 2.9.1.finalで試してみたけど、どれも同じ挙動だった。