Una especie de pregunta de novato de programación funcional aquí:
He estado leyendo las transcripciones de algunas de las charlas de Rich Hickey, y en varias de sus más conocidas, recomienda usar colas como una alternativa a que las funciones se llamen entre sí. (Por ejemplo, en diseño, composición y rendimiento y en Simple Made Easy ).
No entiendo esto, en varios aspectos:
¿Está hablando de poner datos en una cola y luego hacer que cada función los use? Entonces, en lugar de que la función A llame a la función B para llevar a cabo su propio cálculo, solo tenemos que la función B abofetea su salida en una cola y luego la función A la toma. O, alternativamente, ¿estamos hablando de poner funciones en una cola y luego aplicarlas sucesivamente a los datos (seguramente no, porque eso implicaría una mutación masiva, ¿verdad? ¿Y también la multiplicación de colas para funciones de arias múltiples, o como árboles o algo así? )
¿Cómo hace eso para simplificar las cosas? Mi intuición sería que esta estrategia crearía más complejidad, porque la cola sería una especie de estado, y luego debe preocuparse "¿y si alguna otra función se coló y puso algunos datos encima de la cola?"
Una respuesta a una pregunta de implementación sobre SO sugiere que la idea es crear un montón de colas diferentes. Entonces cada función pone su salida en su propia cola (??). Pero eso también me confunde, porque si está ejecutando una función una vez, entonces ¿por qué necesita una cola para su salida cuando podría tomar esa salida y darle un nombre como (var, átomo, entrada en una gran tabla hash, lo que sea). Por el contrario, si una función se ejecuta varias veces y pega su salida en una cola, entonces se ha infligido nuevamente el estado y debe preocuparse por el orden en que se llama todo, las funciones posteriores se vuelven menos puras, etc.
Claramente no entiendo el punto aquí. ¿Alguien puede explicar un poco?
fuente

Jobobjeto genérico , lo inserta en una cola y hace que uno o más subprocesos de trabajo trabajen en esa cola. ElJobentonces despacha másJobs en la cola al finalizar. Los valores de retorno se reemplazan por devoluciones de llamada en ese concepto. Es una pesadilla depurar y verificar, ya que carece de una pila de llamadas, y eficiente y flexible por la misma razón.Respuestas:
Es más un ejercicio de diseño que una recomendación general. Por lo general, no va a poner una cola entre todas sus llamadas a funciones directas. Eso sería ridículo. Sin embargo, si no diseña sus funciones como si se pudiera insertar una cola entre cualquiera de las llamadas a funciones directas, no puede justificar justificadamente que ha escrito código reutilizable y composable. Ese es el punto que Rich Hickey está haciendo.
Esta es una razón importante detrás del éxito de Apache Spark , por ejemplo. Usted escribe código que parece que está haciendo llamadas directas a funciones en colecciones locales, y el marco traduce ese código en mensajes que pasan en colas entre nodos del clúster. El tipo de codificación simple, composable y reutilizable que Rich Hickey defiende lo hace posible.
fuente
Una cosa a tener en cuenta es que la programación funcional le permite conectar funciones entre sí indirectamente a través de objetos mediadores que se encargan de obtener argumentos para alimentar las funciones y enrutar de manera flexible sus resultados a los destinatarios que desean sus resultados. Supongamos que tiene un código de llamada directa directo que se parece a este ejemplo, en Haskell:
Bueno, usando de Haskell
Applicativeclase y sus<$>y<*>operadores podemos volver a escribir mecánicamente ese código para esto:... donde ahora
myThingya no está llamando directamentefyg, sino más bien de conectarlos a través de algunos mediadores de tipof. Entonces, por ejemplo,fpodría ser algúnStreamtipo proporcionado por una biblioteca que proporciona una interfaz a un sistema de colas, en cuyo caso tendríamos este tipo:Sistemas como este existen. De hecho, puede ver las secuencias de Java 8 como una versión de este paradigma. Obtienes un código como este:
Aquí está utilizando las siguientes funciones:
t -> t.getType() == Transaction.GROCERYcomparing(Transaction::getValue).reversed()Transaction::getIdtoList()... y en lugar de hacer que se llamen directamente, está utilizando el
Streamsistema para mediar entre ellos. Este ejemplo de código no llama a laTransaction::getIdfunción directamente,Streamsino a las transacciones que sobrevivieron a la anteriorfilter. Puede pensar en elStreamcomo un tipo de cola muy mínimo que combina funciones indirectamente y enruta valores entre ellas.fuente