2010-08-29 26 views
16

Por el momento, estoy tratando de entender la Programación Funcional en Scala y me encontré con un problema que no puedo resolver.Uso correcto de listas mutables/inmutables

Imagine la siguiente situación:

Existen dos clases: Controlador y Motor de búsqueda. Un Bot es un Actor independiente que se inicia con un controlador , realiza alguna operación costosa y devuelve el resultado al controlador . El propósito del controlador es, por lo tanto, fácil de describir: crea una instancia de varios objetos de Bot, inícialos y recibe el resultado.

Hasta ahora, muy bien; Puedo implementar todo esto sin usar ningún objeto mutable.

Pero ¿qué hago, si tengo que guardar el resultado de que un Bot retornos, para usarlo posteriormente como entrada para otro Bot (y más tarde significa que No sé cuando en ¡tiempo de compilación!)?

Hacer esto con una lista o colección mutable es bastante fácil, pero agrego muchos problemas a mi código (ya que estamos tratando con la concurrencia aquí).

¿Es posible, siguiendo el paradigma de FP, resolver esto utilizando objetos inmutables (listas ...) de forma segura?

Por cierto, soy nuevo FP, por lo que esta pregunta puede sonar estúpido, pero no puedo encontrar la manera de resolver esto :)

Respuesta

6

Esto es como un actor Erlang-como podría parecer en Scala:

case class Actor[State](val s: State)(body: State => Option[State]) { // immutable 
    @tailrec 
    def loop(s1: State) { 
    body(s1) match { 
     case Some(s2) => loop(s2) 
     case None =>() 
    } 
    } 

    def act = loop(s) 
} 

def Bot(controller: Actor) = Actor(controller) { 
    s => 
    val res = // do the calculations 
    controller ! (this, res) 
    None // finish work 
} 

val Controller = Actor(Map[Bot, ResultType]()) {s => 
    // start bots, perhaps using results already stored in s 
    if ( 
    // time to stop, e.g. all bots already finished 
) 
    None 
    else 
    receive { 
     case (bot, res) => Some(s + (bot -> res)) // a bot has reported result 
    } 
} 

Controller.act 
+0

Gracias por esta respuesta. ¡Jugué con tu ejemplo y lo modifiqué según mis necesidades, y parece ser la solución perfecta para mi problema específico! –

7

Los actores suelen tener estado interno, de ser, ellos mismos, bestias mutables. Tenga en cuenta que los actores no son una cosa de FP.

La configuración que describes parece depender de un controlador mutable, y es difícil esquivarla en un idioma que no es estricto de manera predeterminada. Dependiendo de lo que estés haciendo, puedes confiar en el futuro. Por ejemplo:

case Msg(info) => 
    val v1 = new Bot !! Fn1(info) 
    val v2 = new Bot !! Fn2(info) 
    val v3 = new Bot !! Fn3(info) 
    val v4 = new Bot !! Fn4(v1(), v2(), v3()) 
    reply(v4()) 

En este caso - porque !! devuelve un Future-v1, v2 y v3 se calcularán en paralelo. El mensaje Fn4 está recibiendo como parámetros los futuros aplicados, lo que significa que esperará hasta que se hayan calculado todos los valores antes de que comience a computar.

Del mismo modo, la respuesta solo se enviará después de que se haya calculado el v4, ya que el futuro también se ha aplicado.

Una forma realmente funcional de hacer estas cosas es la programación reactiva funcional, o FRP para abreviar. Es un modelo diferente que los actores.

La belleza de Scala, sin embargo, es que puede combinar tales paradigmas en la medida que mejor se adapte a su problema.

+0

Gracias en primer lugar, la cosa "futuro" es nuevo para mí y voy a mirar en él, aunque creo que podría realmente no me ayuda ... Pero, ante todo, echaré un vistazo a FRP, que puede ser la respuesta a todos mis problemas (ya que quiero aprender FP, no el uso de Actors :)) –

+0

"y es difícil evitarlo en un idioma que no es no estricto por defecto "Puedes hacer lo que hace Erlang: pasar el estado como un parámetro a una función recursiva de cola. –

+0

@Alexey No estoy seguro exactamente cómo funcionaría eso. ¿Por qué no dar una respuesta con un ejemplo? –