2011-06-25 16 views
6

W dalszym ciągu próbuję nauczyć się scala, pracuję nad "Scala by example" przez Odersky'ego oraz w rozdziale o funkcjach pierwszorzędnych, sekcja o anonimowej funkcji unika sytuacji rekurencyjnej anonimowej funkcji. Mam rozwiązanie, które wydaje się działać. Ciekaw jestem, czy istnieje lepsza odpowiedź.Jak pisać rekurencyjne anonimowe funkcje?

Z PDF: kodeksu do zaprezentowania funkcja wyższego rzędu

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 

z PDF: Kod do zaprezentowania anonimowych funkcje

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 

Mój kod:

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

Jesteś tego pewien? 'echo" 2^2 + 3^2 "| bc -l' -> '13'. – sarnold

+0

To jest duplikat http://stackoverflow.com/questions/5337464/anonymous-recursive-function-in-scala – Suroot

+1

@ Srebrna Suma Mocy Dwóch - tj. '2^a + 2^a + 1 + ... 2^b-1 + 2^b' '2^2 + 2^3 = 4 + 8 = 12' –

Odpowiedz

13

Dla co to jest warte ... (tytuł i "prawdziwe pytanie" nie całkiem zgadzają)

rekurencyjne anonimowych funkcyjnego przedmioty mogą być utworzone przez „długiej” strony wystającego FunctionN, a następnie za pomocą this(...) wewnątrz apply.

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

Jednak liczba icky-ności to na ogół wprowadza sprawia, że ​​podejście zazwyczaj mniej niż idealne. Najlepiej po prostu użyć „nazwa” i mieć trochę bardziej opisową, modułowe kod - to nie po to bardzo dobry argument za takim ;-)

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

Szczęśliwy kodowania.

2

Można uogólnić tę pośrednią rekursji do:

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

Teraz suma może być zapisana za pomocą rekurencji pośredniej jak:

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

To samo rozwiązanie może być wykorzystane do realizacji memoization na przykład.