read putstrln inputs haskell io command-line-arguments referential-transparency

inputs - putstrln haskell



¿Por qué son las acciones getArgs y getProgName IO? (3)

Soy un completo novato que actualmente intenta aprender Haskell con " Learn You a Haskell for Great Good ". Llegué a la sección que explica cómo trabajar con los argumentos de la línea de comandos , y algo me está molestando.

Desde mi entendimiento (y la definición de haskell.org ), las acciones están destinadas a resumir los efectos secundarios. Los argumentos de la línea de comando son entradas inmutables para una instancia determinada del programa, entonces ¿cuál es el punto de tener getProgName :: IO String lugar de getProgName :: String ? Dicho de otra manera: ¿para qué getProgName evitar que una función pura llame a getProgName ?

Actualizar

Tuve algunas grandes respuestas a esta pregunta hasta ahora. Estoy aceptando la de Don Stewart como la más simple y concisa, pero la de Conal''s (con su publicación de blog asociada) definitivamente vale la pena leerla.


En primer lugar, getArgs puede cambiar en tiempo de ejecución. Ver con withArgs .

En segundo lugar, getArgs y getProgName una interesante clase de cálculos impuros: se consideran como constantes durante la ejecución de un programa, sin embargo, no están disponibles los valores en el momento de la compilación y cambian de una ejecución de un programa a otra. No tienen una denotación limpia.

Ver, por ejemplo, discussions anteriores, donde se discuten getArgs y cálculos de punto flotante. E incluso se puede pensar que minBound / maxBound está en esta clase.


Mi entendimiento es que las funciones puras son puras porque puedes razonar con ellas en "tiempo de código", y el compilador puede, en tiempo de compilación. Las acciones de IO dependen del tiempo de ejecución. getArgs , que le da argumentos a un programa solo cuando se ejecuta, es por lo tanto una acción de IO.

Como Learn you a Haskell lo pone:

Puede pensar en una acción de E / S como una caja con pies pequeños que saldrá al mundo real y hará algo allí (como escribir un graffiti en una pared) y tal vez recuperar algunos datos.

No sabemos qué traerá la caja con pies pequeños en el tiempo de código o de compilación.


Para responder a estas preguntas, necesitará una base: ¿qué significa que una expresión e tiene el tipo t ? Podría dar respuestas arbitrarias para primitivas como getProgName , pero no tiene que hacerlo. En su lugar, mira los significados de las expresiones y de los tipos. Digamos que una expresión e tiene el tipo t cuando el valor denotado por e (es decir, el significado de e como un valor matemático) pertenece a la colección denotada por t .

Ahora considera t == String . ¿Qué significado queremos que tenga String ? Una vez más, hay mucho espacio para elegir aquí. Sin embargo, hay mucho mérito en elegir al candidato útil con la definición matemática más simple. En Haskell String == [Char] , realmente estamos hablando de los significados de [] y Char Los candidatos simples más convincentes que conozco son que [] denota listas (secuencias), y Char denota caracteres, y en consecuencia que String Denota secuencias de caracteres, es decir, "cadenas".

Con la opción de que String significa cadenas, ahora estamos en posición de preguntar si es posible que getProgName :: String . Si es así, entonces el significado de getProgName debe ser una secuencia de caracteres. Sin embargo, no hay una secuencia única de caracteres que capture la intención detrás de getProgName . ( Edición : Es de suponer que desea que getProgName produzca cadenas diferentes cuando aparezca en programas con nombres diferentes). Por lo tanto, debemos elegir un tipo diferente, como (pero no necesariamente) una IO String , o debemos elegir una más Significado complicado para String . La última ruta puede parecer atractiva al principio, hasta que considere las implicaciones profundas. La programación puramente funcional (con más precisión "denotativa") admite un razonamiento práctico y riguroso gracias al uso de significados simples como secuencias en lugar de significados complejos como funciones de algún tipo de entorno, incluido el sistema operativo, el contexto de ejecución de la máquina.

Para comentarios y discusiones estrechamente relacionadas, vea la publicación en el blog Nociones de pureza en Haskell .

Edit: Creo que Peter Landin (abuelo de Haskell) lo expresó mejor con su definición de "programación denotativa" (o "programación genuinamente funcional"), que recomendó como un reemplazo sustantivo a términos vagos como programación "declarativa" y "funcional". . Para una referencia, citas y un breve comentario, vea este comentario en la publicación ¿Es Haskell un lenguaje puramente funcional? .