2011-06-25 98 views
6

在我繼續努力學習scala的過程中,我正在通過Odersky的「Scala by Example」以及關於第一類函數的章節,匿名函數部分避免了遞歸匿名函數的情況。我有一個似乎可行的解決方案。我很好奇,如果有更好的答案。如何編寫遞歸匿名函數?

從PDF: 代碼展示高階函數

def sum(f: Int => Int, a: Int, b: Int): Int = 
    if (a > b) 0 else f(a) + sum(f, a + 1, b) 

def id(x: Int): Int = x 
def square(x: Int): Int = x * x 
def powerOfTwo(x: Int): Int = if (x == 0) 1 else 2 * powerOfTwo(x-1) 

def sumInts(a: Int, b: Int): Int = sum(id, a, b) 
def sumSquares(a: Int, b: Int): Int = sum(square, a, b) 
def sumPowersOfTwo(a: Int, b: Int): Int = sum(powerOfTwo, a, b) 

scala> sumPowersOfTwo(2,3) 
res0: Int = 12 

從PDF: 代碼展示匿名函數

def sum(f: Int => Int, a: Int, b: Int): Int = 
    if (a > b) 0 else f(a) + sum(f, a + 1, b) 

def sumInts(a: Int, b: Int): Int = sum((x: Int) => x, a, b) 
def sumSquares(a: Int, b: Int): Int = sum((x: Int) => x * x, a, b) 
// no sumPowersOfTwo 

我的代碼:

def sumPowersOfTwo(a: Int, b: Int): Int = sum((x: Int) => { 
    def f(y:Int):Int = if (y==0) 1 else 2 * f(y-1); f(x) }, a, b) 

scala> sumPowersOfTwo(2,3) 
res0: Int = 12 
+0

你確定嗎? 'echo「2^2 + 3^2」| bc -l' - >'13'。 – sarnold

+0

這是一個重複http://stackoverflow.com/questions/5337464/anonymous-recursive-function-in-scala – Suroot

+1

@sarnold兩個權力之和 - 即'2^a + 2^a + 1 + ... 2^b-1 + 2^b'' 2^2 + 2^3 = 4 + 8 = 12' –

回答

13

對於什麼是值得的...(標題和「真正的問題」不完全同意)

遞歸匿名功能的對象可以通過FunctionN,然後使用this(...)內部apply的延伸的「長手」被創建。

(new Function1[Int,Unit] { 
    def apply(x: Int) { 
    println("" + x) 
    if (x > 1) this(x - 1) 
    } 
})(10) 

但是,這種通常引入的不規則性使得該方法通常不夠理想。最好只用一個「名」,並有一些描述性的,模塊化的代碼 - 不,下面就是這樣;-)

val printingCounter: (Int) => Unit = (x: Int) => { 
    println("" + x) 
    if (x > 1) printingCounter(x - 1) 
} 
printingCounter(10) 

快樂編碼一個很好的理由。

2

可以概括這種間接遞歸:

case class Rec[I, O](fn : (I => O, I) => O) extends (I => O) { 
    def apply(v : I) = fn(this, v) 
} 

現在和可以使用間接遞歸作爲被寫成:

val sum = Rec[Int, Int]((f, v) => if (v == 0) 0 else v + f(v - 1)) 

同樣的解決方案可以被用來實現例如記憶化。