Ich wollte das memoize:Gibt es eine generelle Möglichkeit, in Scala zu memoisieren?
def fib(n: Int) = if(n <= 1) 1 else fib(n-1) + fib(n-2)
println(fib(100)) // times out
Also schrieb ich das und das kompiliert raschend und arbeitet (ich bin überrascht, weil fib
Referenzen selbst in seiner Erklärung):
case class Memo[A,B](f: A => B) extends (A => B) {
private val cache = mutable.Map.empty[A, B]
def apply(x: A) = cache getOrElseUpdate (x, f(x))
}
val fib: Memo[Int, BigInt] = Memo {
case 0 => 0
case 1 => 1
case n => fib(n-1) + fib(n-2)
}
println(fib(100)) // prints 100th fibonacci number instantly
Aber wenn ich versuche, erklären fib innerhalb eines def
, ich habe einen Compiler-Fehler:
def foo(n: Int) = {
val fib: Memo[Int, BigInt] = Memo {
case 0 => 0
case 1 => 1
case n => fib(n-1) + fib(n-2)
}
fib(n)
}
Above nicht kompilieren error: forward reference extends over definition of value fib case n => fib(n-1) + fib(n-2)
Warum funktioniert die Deklaration der val fib
in einem Def-Fehler aber außerhalb in der Klasse/Objekt-Bereich funktioniert?
Um zu klären, warum ich die rekursive memoized Funktion im def Umfang erklären möchte - hier ist meine Lösung für die Teilmenge Summe Problem:
/**
* Subset sum algorithm - can we achieve sum t using elements from s?
*
* @param s set of integers
* @param t target
* @return true iff there exists a subset of s that sums to t
*/
def subsetSum(s: Seq[Int], t: Int): Boolean = {
val max = s.scanLeft(0)((sum, i) => (sum + i) max sum) //max(i) = largest sum achievable from first i elements
val min = s.scanLeft(0)((sum, i) => (sum + i) min sum) //min(i) = smallest sum achievable from first i elements
val dp: Memo[(Int, Int), Boolean] = Memo { // dp(i,x) = can we achieve x using the first i elements?
case (_, 0) => true // 0 can always be achieved using empty set
case (0, _) => false // if empty set, non-zero cannot be achieved
case (i, x) if min(i) <= x && x <= max(i) => dp(i-1, x - s(i-1)) || dp(i-1, x) // try with/without s(i-1)
case _ => false // outside range otherwise
}
dp(s.length, t)
}
Siehe meine [Blogpost] (http://michid.wordpress.com/2009/02/23/function_mem/) für eine andere Variante für die Memoisierung von r ecursive Funktionen. – michid
Bevor ich etwas posten SO, ich es und Ihr Blog-Eintrag war Google das erste Ergebnis :) Es ist der „richtige“ Weg, dies stimme ich zu tun - mit dem Y-Combinator. Aber ich denke, dass die Verwendung meines Stils und das Ausnutzen von 'Lazy Val' sauberer ist, als zwei Definitionen (die rekursive und die Y-Kombination) für jede Funktion zu haben. Sieht aus wie sauber diese [sieht] (1) [1]: https://github.com/pathikrit/scalgos/blob/master/src/main/scala/com/github/pathikrit/scalgos/Combinatorics.scala# . L67 – pathikrit
ich wurde von einigen der Prägnanz der Syntax in Ihr Problem oben (insbesondere der Fall Klasse Verwendung von „erweitern (A => B)“ verwirrt ich eine Frage über sie geschrieben: http://stackoverflow.com/questions/19548103/in-scala-what-tut-sie-ab-on-a-case-Klasse-mean – chaotic3quilibrium