Perdón por otra pregunta de efectos secundarios de FP +, pero no pude encontrar una existente que respondiera esto por mí.
Mi comprensión (limitada) de la programación funcional es que los efectos de estado / secundarios deben minimizarse y mantenerse separados de la lógica sin estado.
También deduzco que el enfoque de Haskell sobre esto, la mónada IO, logra esto envolviendo acciones con estado en un contenedor, para su posterior ejecución, considerado fuera del alcance del propio programa.
Estoy tratando de entender este patrón, pero en realidad para determinar si usarlo en un proyecto de Python, así que quiero evitar los detalles de Haskell si es posible.
Crudo ejemplo entrante.
Si mi programa convierte un archivo XML en un archivo JSON:
def main():
xml_data = read_file('input.xml') # impure
json_data = convert(xml_data) # pure
write_file('output.json', json_data) # impure
¿No es el enfoque de la mónada IO para hacer esto de manera efectiva?
steps = list(
read_file,
convert,
write_file,
)
entonces, ¿se absuelve de la responsabilidad al no llamar a esos pasos, sino al permitir que el intérprete lo haga?
O dicho de otra manera, es como escribir:
def main(): # pure
def inner(): # impure
xml_data = read_file('input.xml')
json_data = convert(xml_data)
write_file('output.json', json_data)
return inner
luego esperar que alguien más llame inner()
y decir que su trabajo está hecho porque main()
es puro.
Todo el programa terminará contenido en la mónada IO, básicamente.
Cuando el código se ejecuta realmente , todo después de leer el archivo depende del estado de ese archivo, por lo que aún sufrirá los mismos errores relacionados con el estado que la implementación imperativa, por lo que ¿ha ganado algo como programador que mantendrá esto?
Aprecio totalmente el beneficio de reducir y aislar el comportamiento con estado, de hecho, es por eso que estructuré la versión imperativa de esa manera: reunir entradas, hacer cosas puras, escupir salidas. Con suerte convert()
puede ser completamente puro y cosechar los beneficios de la capacidad de almacenamiento en caché, seguridad de hilos, etc.
También aprecio que los tipos monádicos pueden ser útiles, especialmente en tuberías que operan en tipos comparables, pero no veo por qué IO debería usar mónadas a menos que ya estén en esa tubería.
¿Hay algún beneficio adicional al tratar con los efectos secundarios que trae el patrón de mónada IO, que me estoy perdiendo?
main
un programa Haskell es IO ()
: una acción de E / S. Esto no es realmente una función en absoluto; Es un valor . Todo el programa es un valor puro que contiene instrucciones que le indican al lenguaje en tiempo de ejecución lo que debe hacer. Todas las cosas impuras (que realmente realizan las acciones de IO) están fuera del alcance de su programa.
read_file
) y lo usa como argumento para el siguiente ( write_file
). Si solo tuvieras una secuencia de acciones independientes, no necesitarías una Mónada.