Marcelo Cantos gave a pretty good explanation, pero creo que se puede hacer un poco más preciso.
Un tipo de cosas se pueden componer cuando se pueden combinar varias instancias de una cierta manera para producir el mismo tipo de cosas.
Capacidad de compilación de la estructura de control. lenguajes como C hacen una distinción entre expresiones, que pueden estar compuestos usando los operadores para producir nuevas expresiones y declaraciones, que puede estar compuesto usando estructuras de control como if
, for
y la "estructura de control de secuencia" que simplemente realiza declaraciones en orden. Lo que ocurre con esta disposición es que estas dos categorías no están en pie de igualdad: muchas estructuras de control utilizan expresiones (por ejemplo, la expresión evaluada por if
para elegir qué rama ejecutar), pero las expresiones no pueden usar estructuras de control (p. no puede devolver un bucle for
). Aunque pueda parecer loco o sin sentido querer "devolver un bucle for
", de hecho, la idea general de tratar las estructuras de control como objetos de primera clase que pueden almacenarse y transmitirse no solo es posible sino también útil. En lenguajes funcionales perezosos como Haskell, las estructuras de control como if
y for
se pueden representar como funciones ordinarias, que pueden manipularse en expresiones como cualquier otro término, habilitando funciones como "construir" otras funciones según los parámetros que se transmiten y devolverlos a la persona que llama. Entonces, mientras C (por ejemplo) divide "las cosas que un programador podría querer hacer" en dos categorías y limita las formas en que se pueden combinar los objetos de estas categorías, Haskell (por ejemplo) tiene una sola categoría y no impone tales límites. , por lo que en este sentido proporciona más capacidad de compilación.
Capacidad de subprocesos. Asumiré, como dijo Marcelo Cantos, que realmente está hablando de la capacidad de compilación de los hilos que usan bloqueos/mutexes. Este es un caso un poco más complicado porque, en vista de ello, puede tener hilos que usan bloqueos múltiples; pero el punto importante es que no podemos tener hilos que usen cerrojos múltiples con la garantía de que están destinados a tener.
Podemos definir un bloqueo como un tipo de cosa que tiene ciertas operaciones que se pueden realizar en él, que vienen con ciertas garantías. Una garantía es: suponga que hay un objeto de bloqueo x
, luego, siempre que cada proceso que llame a lock(x)
eventualmente llame a unlock(x)
, cualquier llamada a lock(x)
eventualmente regresará con éxito con x
bloqueado por el proceso/proceso actual. Esta garantía simplifica enormemente el razonamiento sobre el comportamiento del programa.
Desafortunadamente, si hay más de un bloqueo en el mundo, ya no es cierto. Si el hilo A llama a lock(x); lock(y);
y el hilo B llama al lock(y); lock(x);
, entonces es posible que A agarre el bloqueo x
y B tome el bloqueo y
y que ambos esperen indefinidamente para que el otro hilo libere el otro bloqueo: punto muerto. Por lo tanto, los bloqueos no son compostables, porque cuando usa más de uno, no puede simplemente afirmar que esa importante garantía aún se mantiene - no sin antes analizar el código en detalle para ver cómo se maneja el bloqueo. En otras palabras, ya no puede darse el lujo de tratar las funciones como "cajas negras".
Las cosas que son componibles son buenas, ya que permiten abstracciones, lo que significa que nos permiten razonar sobre el código sin tener que preocuparse por todos los detalles, y que reduce la carga cognitiva en el programador.
+1. Bonito * "Las cosas que se pueden componer son buenas porque permiten abstracciones, lo que significa que nos permiten razonar sobre el código sin tener que preocuparnos por todos los detalles, y eso reduce la carga cognitiva del programador." * – Nawaz
expandiéndose un poco directamente en Las viñetas de op: Nunca escuché "los hilos no son compostables", pero un ejemplo de una abstracción delgada y composable que se puede construir fácilmente _atop_ hilos son [async/promises] (https://hackage.haskell.org/package/async). Re. las mónadas solo necesitan observar el tipo de enlace: '>> = :: Monad m => m a -> (a -> m b) -> m b'. – jberryman
Después de 3 años, leí esta respuesta ** de nuevo ** y ahora creo que la entiendo mejor de lo que lo entendí la última vez. En particular, puedo imaginar varias cosas que se relacionan con esto * "Un tipo de cosa es composable cuando se pueden combinar varias instancias de una cierta manera para producir el mismo tipo de cosas." * ... y varias otras que no (significa cosas que no son compostables). Una vez más, ¡gracias por esta increíble respuesta! – Nawaz