3

関数型プログラミングの Scalaforeverのコンビネータを見ると、次のようになります。

trait AddlCombinators[F[_]] extends Monad[F] with Functor[F] {
      def forever[A, B](a: F[A]): F[B] = {
        lazy val t: F[B] = forever(a)
        flatMap(a)(_ => t)
      }
}

本で説明されているように、StackOverflow に遭遇しました。

次に、変数を追加し、アクセスされるcountたびにインクリメントします。t

var count = 0
def forever[A, B](a: F[A]): F[B] = {
  lazy val t = { println(count); count = count + 1; forever(a) }
}

次に、ScalaTest テストを作成しました。

 "running forever" should "throw a StackOverflow exception" in {
        val listCombinator = new AddlCombinators[List] {

        // omitted implementation of `Monad[List]` and `Functor[List]`
        }    
        listCombinator.forever(List(1))
      }
}

上記のテストを 3 回実行した後、毎回 ~1129/1130 で失敗します。

1129
[info] TestCombinators:
[info] running forever
[trace] Stack trace suppressed: run last test:testOnly for the full output.
[error] Could not run test test.TestCombinators: java.lang.StackOverflowError

なぜクラッシュする前にその数に達しているのでしょうか? また、各実行が占有するスタックメモリの量をどのように判断できますforeverか?

4

1 に答える 1

2

スタックサイズのため、最大でその数になります。サイズは で設定でき-Xss、デフォルト値はプラットフォームおよび VM/バージョンによって異なります。しかし、一般に、エラーが発生したStackOverflowError場合は、設定ではなくコードで問題を修正する必要があります。この場合、トランポリンを使用してスタックのオーバーフローを防ぎます。非常に良い説明がここにあります: http://blog.higher-order.com/assets/trampolines.pdf

于 2014-02-25T08:36:44.770 に答える