Почему я получаю бесконечный цикл при использовании неявных преобразований? - PullRequest
2 голосов
/ 08 июля 2011

Контекст

object Fibonacci {
  final val Threshold = 30

  def fibonacci(n: Int)(implicit implementation: Fibonacci): Int = implementation match {
    case f: functional.type if n > Threshold => fibonacci(n)(imperativeWithLoop) 
    case f: imperativeWithRecursion.type => f(n)
    case f: imperativeWithLoop.type => f(n)
    case f: functional.type => f(n)
  }

  sealed abstract class Fibonacci extends (Int => Int)

  object functional extends Fibonacci {
    def apply(n: Int): Int =
      if (n <= 1) n else apply(n - 1) + apply(n - 2)
  }

  object imperativeWithRecursion extends Fibonacci {
    def apply(n: Int) = {
      @scala.annotation.tailrec
      def recursion(i: Int, f1: Int, f2: Int): Int =
        if (i == n) f2 else recursion(i + 1, f2, f1 + f2)

      if (n <= 1) n else recursion(1, 0, 1)
    }
  }

  implicit object imperativeWithLoop extends Fibonacci {
    def apply(n: Int) = {
      def loop = {
        var res = 0
        var f1 = 0
        var f2 = 1
        for (i <- 2 to n) {
          res = f1 + f2
          f1 = f2
          f2 = res
        }
        res
      }

      if (n <= 1) n else loop
    }
  }
}

Пример

object Main extends App { // or REPL
  import Fibonacci._
  println(fibonacci(6)(imperativeWithRecursion)) // 8
  println(fibonacci(6)(imperativeWithLoop)) // 8
  println(fibonacci(6)(functional)) // 8
  println(fibonacci(6)) // 8
  println(fibonacci(40)(functional)) // 102334155
}

Объяснение Я играл со Scala и закончилс этим кодом.Он компилируется и запускается, но ...

Вопросы:

1) Есть ли разница (читаемость, производительность, известные ошибки, что угодно) между

case f: functional.type => f(n)

и

case `functional` => functional(n)

Это должно быть больше обсуждением, так что меня интересуют не только факты.Любое мнение приветствуется.

2) Посмотрите на первую строку метода fibonacci.Вот оно:

case f: functional.type if n > Threshold => fibonacci(n)(imperativeWithLoop)

Если я опускаю второй список параметров (imperativeWithLoop), код компилируется, но входит в бесконечный цикл, когда я его запускаю.Кто-нибудь знает почему?Реализация по умолчанию imperativeWithLoop известна компилятору (ошибок не возникает).Так почему же он не вызывается неявно?(Я предполагаю, что это не так)

1 Ответ

3 голосов
/ 08 июля 2011

Что касается первого вопроса, то здесь есть небольшие различия, но они не имеют значения.Но было бы лучше, если бы вы прописали объекты в верхнем регистре, и тогда вы могли бы написать это:

case Functional => Functional(n)

Что касается второго вопроса, если вы пропустите imperativeWithLoop, он выберет неявное Fibonacci ближайшийв области действия - implementation (которая уже была найдена равной funcional).Поэтому он будет вызывать себя с точно такими же параметрами, как и ранее, и, следовательно, входит в бесконечный цикл.

...