¿Por qué acceder a System.Info no se considera una operación de E / S en Haskell?

25

En el módulo System.Infoveo estas funciones:

os :: String
arch :: String
compilerName :: String
compilerVersion :: Version

¿Por qué no hay IOallí? Están accediendo al sistema ... ¿Me equivoco? Mi expectativa era algo así como:

os :: IO String
arch :: IO String
compilerName :: IO String
compilerVersion :: IO Version

Caso de uso:

      print os            -- "darwin"
      print arch          -- "x86_64"
      print compilerName  -- "ghc"
Francisco Albert
fuente

Respuestas:

29

No obtienes esa información en tiempo de ejecución . Están codificados en el compilador tal como está instalado en su sistema.

Esto es más obvio si observa la definición compilerNameque se encuentra en http://hackage.haskell.org/package/base-4.12.0.0/docs/src/System.Info.html .

compilerName :: String
compilerName = "ghc"

pero incluso algo como os

os :: String
os = HOST_OS

se define en términos de un nombre indefinido HOST_OS(un valor que comienza con una letra mayúscula ??) que sugiere que es solo un marcador de posición que se reemplaza durante la instalación.

Alguien también puede corregirme (¡por favor!), Pero el {-# LANGUAGE CPP #-}pragma en la parte superior de ese archivo sugiere que, HOST_OSy similares, son reemplazados por las cadenas apropiadas por el preprocesador C antes de la compilación.

chepner
fuente
2
Si el OP realmente quiere algo IOallí, hay un envoltorio uname(3)disponible en Hackage: hackage.haskell.org/package/bindings-uname
thsutton
19

La pregunta es buena. La respuesta, tal como es, es que esos valores son estáticos por compilación del programa. Básicamente se compilan en el programa y nunca cambian después de eso. Como tal, nada (en los supuestos que usa GHC) se rompe si los trata como constantes. Y es más conveniente usar una constante simple que una acción IO.

Pero eso es todo tipo de razonamiento heredado. Haskell es un idioma antiguo. (No, en realidad, es más antiguo que Java por varios años). Se han creado muchas bibliotecas con razonamientos que ya no se consideran las mejores prácticas. Estos son ejemplos de eso. Una biblioteca moderna que los exponga probablemente los convierta en acciones de E / S aunque los resultados no cambien después de la compilación. Es más útil poner cosas que no son constantes en el nivel de origen detrás de las acciones de IO, aunque todavía hay algunas excepciones notables, como Intcambiar el tamaño entre las plataformas de 32 y 64 bits.

En cualquier caso ... Diría que sus expectativas son sólidas, y esos tipos son el resultado de rarezas históricas.

Carl
fuente
-9

EDITAR: Gracias a @interjay y @Antal Spector-Zabusky por explicar por qué se rechaza esta respuesta. Ellos escribieron

La documentación es un poco engañosa. Los valores están codificados en el compilador GHC. Después de 48 años, seguramente sabrá que el código real siempre supera la documentación. - Interjay ayer @ andy256 Tienes toda la razón de que la documentación es mala (de hecho, eso es parte de por qué Francisco hizo esta pregunta en primer lugar), y tu confusión es comprensible. Lo que pasa con Haskell es que si esos valores de cadena pueden variar en tiempo de ejecución, eso sería un error notorio: las variables no pueden cambiar. Este es el significado del constructor de tipo IO: representa un cálculo al que se le permite acceder al "mundo exterior" y, por lo tanto, uno cuyo resultado puede cambiar. Hacer una llamada al sistema es un buen ejemplo de una acción IO. ... [1/2] - Antal Spector-Zabusky hace 9 horas @ andy256 ... (Otra acción de E / S podría ser "actualizar un contador global".) Entonces, cuando vemos una Cadena, sabemos que no se puede comunicar con El sistema operativo bajo el capó. Esta es la razón por la cual, quizás sorprendentemente, si no está acostumbrado a Haskell, no sería fácil implementar os :: String para hacer una llamada al sistema: cualquier valor de este tipo no es implementable en Haskell básico, violaría las expectativas de cada programador de cómo los programas trabajo, y posiblemente incluso disparar el compilador y el optimizador (no es una preocupación teórica, hay respuestas de desbordamiento de pila donde las personas se encuentran con problemas análogos). [2/2] - Antal Spector-Zabusky Esta es la razón por la cual, quizás sorprendentemente, si no está acostumbrado a Haskell, no sería fácil implementar os :: String para hacer una llamada al sistema: cualquier valor de este tipo no es implementable en Haskell básico, violaría las expectativas de cada programador de cómo los programas trabajo, y posiblemente incluso disparar el compilador y el optimizador (no es una preocupación teórica, hay respuestas de desbordamiento de pila donde las personas se encuentran con problemas análogos). [2/2] - Antal Spector-Zabusky Esta es la razón por la cual, quizás sorprendentemente, si no está acostumbrado a Haskell, no sería fácil implementar os :: String para hacer una llamada al sistema: cualquier valor de este tipo no es implementable en Haskell básico, violaría las expectativas de cada programador de cómo los programas trabajo, y potencialmente incluso disparar el compilador y el optimizador (no es una preocupación teórica, hay respuestas de desbordamiento de pila donde las personas se encuentran con problemas análogos). [2/2] - Antal Spector-Zabusky y potencialmente incluso disparar el compilador y el optimizador (no es una preocupación teórica, hay respuestas de desbordamiento de pila donde las personas se encuentran con problemas análogos). [2/2] - Antal Spector-Zabusky y potencialmente incluso disparar el compilador y el optimizador (no es una preocupación teórica, hay respuestas de desbordamiento de pila donde las personas se encuentran con problemas análogos). [2/2] - Antal Spector-Zabusky

Actualmente tiene dos votos eliminados. Dejaré que el proceso siga su curso, pero sugiero que en realidad tiene algún valor. En una nota al margen, sus explicaciones muestran que la pregunta era débil, y también lo son las respuestas, ya que un novato de Haskell podría seguir fácilmente el razonamiento que hice.

Respuesta original:

No soy un programador de Haskell, pero las dos respuestas ya dadas no coinciden con la documentación que el OP enlazó.

Mi interpretación de la documentación sigue.

os :: String - Esto le proporciona "El sistema operativo en el que se ejecuta el programa".

Espero que esto emita una llamada al sistema para obtener la información. Debido a que el sistema en el que se compila el programa puede ser diferente del que se ejecuta, no puede ser un valor insertado por el compilador. Si el código se está interpretando, el intérprete puede proporcionar el resultado, que debe obtenerse a través de una llamada al sistema.

arch :: String - Esto le proporciona "La arquitectura de la máquina en la que se ejecuta el programa".

Nuevamente, espero que esto emita una llamada al sistema para obtener la información. Debido a que el sistema en el que se compila el programa puede ser diferente del que se ejecuta, no puede ser un valor insertado por el compilador.

compilerName :: String - Esto le brinda "La implementación de Haskell con la que se compiló el programa o se está interpretando".

Este valor es ciertamente insertado por el compilador / intérprete.

compilerVersion :: String- Esto le proporciona "La versión compilerNamecon la que se compiló el programa o se está interpretando".

Este valor es ciertamente insertado por el compilador / intérprete.

Si bien puede considerar que las dos primeras llamadas obtienen información, el resultado proviene de los valores que posee el sistema operativo. E / S generalmente se refiere al acceso al almacenamiento secundario.

andy256
fuente
3
No es cierto para Haskell. Aquí, cualquier cálculo no está ordenado y su resultado puede almacenarse en caché. Las funciones son puras, por lo que si una función no acepta argumentos, es muy similar a una constante. Las funciones de un argumento parecen simples hashmaps o diccionarios, que calculan el valor en función de la clave. No puede usar un entorno externo, hacer llamadas al sistema en tales funciones, ni siquiera puede obtener un número aleatorio o una fecha actual. Pero si realmente quieres usar esa "secuencia" o entorno, entonces necesitas usar IOmónada para emular el estado, emular la secuencia de operaciones
Yuri Kovalenko
"No se puede usar un entorno externo, hacer syscalls en tales funciones" - ¡Claro que sí, especialmente si "usted" es el compilador de Haskell! Sería muy fácil implementar una implementación de Haskell os :: Stringpara que haga una llamada al sistema cuando se evalúa.
Tanner Swett el
2
No creo que entiendas el significado de la mónada IO en Haskell.
Sneftel
@Sneftel Usted es, por supuesto, correcto. Elegí responder porque después de 48 años de programación en cada paradigma, y ​​escribiendo el compilador extraño, las respuestas iniciales no coincidían con la documentación, y aún no lo hacen. Dice claramente eso osy archse obtienen en tiempo de ejecución.
andy256
1
La documentación es un poco engañosa. Los valores están codificados en el compilador GHC. Después de 48 años, seguramente sabrá que el código real siempre supera la documentación.
Interjay