2010-09-17 17 views
18

En el fragmento de código se incluye a continuación, tengo una llamada de función recursiva, que se utiliza para facilitar un reintento si falla una llamada de red (Amazon SimpleDB de vez en cuando devolver un 503 y requieren de reintento.)¿Por qué Scala requiere un tipo de devolución para funciones recursivas?

Cuando intento compilar, el Scala se queja recursive method simpledb_update needs result type.

// sends data to SimpleDB. Retries if necessary 
def simpledb_update(name: String, metadata: Map[String,String], attempt: Int) = { 
try { 
    db(config("simpledb_db")) += (name, metadata) 
} catch { 
    case e => 
    // if it fails, try again up to 5 times 
    if(attempt < 6) 
    { 
    Thread.sleep(500) 
    simpledb_update(name, metadata, attempt + 1) 
    } else 
    AUlog(name + ": SimpleDB Failed") 
    } 
} 

¿Por qué es necesario en las funciones recursivas? Mi idea es simplemente devolver un booleano verdadero/falso para satisfacer al compilador ... las siguientes compilaciones están bien.

// sends data to SimpleDB. Retries if necessary 
def simpledb_update(name: String, metadata: Map[String,String], attempt: Int): Boolean = { 
try { 
    db(config("simpledb_db")) += (name, metadata) 
    true 
} catch { 
    case e => 
    // if it fails, try again up to 5 times 
    if(attempt < 6) 
    { 
    Thread.sleep(500) 
    simpledb_update(name, metadata, attempt + 1) 
    } else 
    AUlog(name + ": SimpleDB Failed") 
    false 
    } 
} 
+1

Similar: http://stackoverflow.com/questions/2209179/type-inference-on-method-return-type – missingfaktor

+4

Psst, si está utilizando 2.8, use 'intento: Int = 0' para que su llamada original no lo haga ¡Necesito especificar que es el intento cero! Además, si haces algo profundamente recursivo, podrías desbordar la pila (6 está bien, por supuesto). Para comprobar si Scala puede evitar el uso de la pila, anótelo con '@ annotation.tailrec' antes de' def'. Si no es recursivo de cola, se debe usar la pila y Scala arrojará un error; al menos sabrá con qué se trata cuando elimine la anotación. –

+0

Viniendo de Ruby, esa fue mi primera inclinación. ¡Ay, estoy en 2.7 ... sin apoyo! Es hora de actualizar, supongo. – Joshua

Respuesta

16

Según tengo entendido, las funciones recursivas necesitan un tipo de retorno porque el algoritmo de inferencia de tipo no es lo suficientemente potente como para determinar los tipos de retorno para todas las funciones recursivas.

Sin embargo, no necesita crear un tipo de devolución, solo necesita declarar el tipo de devolución que ya estaba utilizando: Unidad. La unidad es un tipo especial con solo un elemento(). También es el tipo de la mayoría de las "declaraciones" en Scala, y es el tipo de devolución para declarar para los métodos que no necesitan devolver nada, pero que se ejecutan solo por sus efectos secundarios (como el suyo). Usted puede declarar su método de devolver la unidad como lo haría con otros tipos

def simpledb_update(name: String, metadata: Map[String,String], attempt: Int):Unit = { 

Más idiomáticamente Scala proporciona una sintaxis especial para los métodos Unidad-regresan, acaba de salir fuera el tipo de retorno y el signo igual

def simpledb_update(name: String, metadata: Map[String,String], attempt: Int){ 

de acuerdo con la guía de estilo Scala se debe preferir el uso del signo igual

http://docs.scala-lang.org/style/declarations.html

+1

¿por qué el algoritmo de inferencia de tipo no es lo suficientemente potente como para determinar los tipos de retorno para todas las funciones recursivas? – CuiPengFei

+0

Literalmente citando "Scala para el impaciente": algunos lenguajes de programación (como ML y Haskell) pueden inferir el tipo de función recursiva, utilizando el algoritmo de Hindley-Milner. Sin embargo, esto no funciona bien en un lenguaje orientado a objetos. Extender el algoritmo de Hindley-Milner para que pueda manejar los subtipos sigue siendo un problema de investigación. – amorales

+0

http://people.inf.ethz.ch/trayteld/papers/aplas11-coercions/coercions_short.pdf – amorales

10

Simplemente elimine el = de la línea y devolverá la Unidad, esto significa que no necesita devolver nada.

def simpledb_update(name: String, metadata: Map[String,String], attempt: Int) { 

Creo que la necesidad de tipos de retorno, para asegurarse de que todas las rutas de recursión tienen el tipo correcto. En una función normal, el tipo se deduciría de todos los puntos de retorno.

+0

Ahhh ... tiene perfecto sentido. – Joshua

+2

Simplemente no puede inferir el tipo de los puntos de retorno, porque al menos uno de los puntos de retorno tiene el tipo que está tratando de inferir. –

+3

@Jorg - En realidad, no es tan difícil de inferir (pero es más difícil de lo que uno podría desear). Si obtiene el tipo de cada valor de retorno de ruta que no es el valor de retorno recursivo, ese debe ser el tipo de valor devuelto. Pero esto se complica cuando se lo empuja a funciones mutuamente recursivas. –

Cuestiones relacionadas