2011-06-25 21 views
6

En mi continuo esfuerzo por aprender scala, estoy trabajando con 'Scala por ejemplo' de Odersky y en el capítulo sobre funciones de primera clase, la sección sobre función anónima evita una situación de función anónima recursiva. Tengo una solución que parece funcionar. Tengo curiosidad si hay una mejor respuesta por ahí.¿Cómo escribo funciones anónimas recursivas?

del PDF: Código de mostrar funciones de orden superior

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 

del pdf: Código de mostrar funciones anónimas

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 

Mi código:

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

¿Estás seguro de eso? 'echo" 2^2 + 3^2 "| bc -l' -> '13'. – sarnold

+0

Esto es un duplicado http://stackoverflow.com/questions/5337464/anonymous-recursive-function-in-scala – Suroot

+1

@sarnold Suma de poderes de dos - es decir '2^a + 2^a + 1 + ... .2^b-1 + 2^b' '2^2 + 2^3 = 4 + 8 = 12' –

Respuesta

13

Para lo que vale ... (el título y la "pregunta real" no terminan de acuerdo)

recursivas de funciones-objetos anónimos se pueden crear a través de la "mano larga" que se extiende de FunctionN y luego usando this(...)apply el interior.

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

Sin embargo, la cantidad de icky-dad esto introduce generalmente hace que el enfoque generalmente menos que ideal. Mejor sólo tiene que utilizar un "nombre" y tienen algo de código más descriptiva y modular - no es que el siguiente es un muy buen argumento para tal ;-)

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

feliz de codificación.

2

Usted puede generalizar esta repetición indirecta a:

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

Ahora suma puede escribirse usando la repetición indirecta como:

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

La misma solución se puede utilizar para implementar memoization por ejemplo.