LoginSignup
1
0

More than 5 years have passed since last update.

Scalaの遅延評価(lazy)を関数オブジェクトで使ってみる

Posted at

概要

Scalaでよく使う遅延評価(lazy)を、関数オブジェクトに適用して、処理効率を上げてみたときの内容をサンプルコードにまとめます。なお、遅延評価の詳細についてはプログラミング言語Scala 日本語情報サイト 第 14 章 遅延評価valを参照ください。

例題

以下が処理効率化する前のサンプルコードです。partitionの中で本来一度で済むはずのOptionの空判定やSeqのlengthメソッドの呼び出しを、ループ回数分だけ行っています。なお、partitionについては@f81@githubさんの第10章:Scalaの「Traversable」リファレンスを参照ください。

Before.scala
  def testBefore(judgeOpt: Option[Int]) = {
    val numberList = Seq(1,2,3,4,5,6,7,8,9,10)

    val (leftList,rightList) = numberList.partition{ n =>
      if (judgeOpt.isEmpty) {
        false
      } else if (judgeOpt.get > numberList.length) {
        true
      } else {
        if (n % judgeOpt.get == 0) {
          false
        } else {
          true
        }
      }
    }
    println(leftList)
  }

lazyを使ったサンプルコード

対応として1つ目と2つ目のブロックをあらかじめBooleanで評価するという手もありますが、今回はlazyを用いて処理の効率化を実現してみます。
下記のサンプルコードの通り、関数オブジェクトを遅延評価する関数(judgeFunction)を作成しpartition内で使用する判定関数を一度の評価で決定します。なお、judgeFunction中の「println("None")」や「println("Over")」は一度しか処理されません。

After.scala
  def testAfter(judgeOpt: Option[Int]) = {
    val numberList = Seq(1,2,3,4,5,6,7,8,9,10)
    def judgeFunction(judgeOpt: Option[Int], list: Seq[Int]):(Int) => Boolean = {
      if (judgeOpt.isEmpty) {
        println("None")
        (_: Int) => false
      } else if (judgeOpt.get > list.length) {
        println("Over")
        (_: Int) => true
      } else {
        divideFuncton(_: Int, judgeOpt.get)
      }
    }
    def divideFuncton(target: Int, input: Int):Boolean = {
      if (target % input == 0) {
        false
      } else {
        true
      }
    }

    lazy val f = judgeFunction(judgeOpt, numberList)
    val (leftList,rightList) = numberList.partition{ n =>
      f(n)
    }
    println(leftList)
  }
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0