Pourquoi l'accès à System.Info n'est-il pas considéré comme une opération d'E / S dans Haskell?

25

Dans le module, System.Infoje vois ces fonctions:

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

Pourquoi n'y en a-t-il pas IO? Ils accèdent au système ... Je me trompe? Mon attente était quelque chose comme:

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

Cas d'utilisation:

      print os            -- "darwin"
      print arch          -- "x86_64"
      print compilerName  -- "ghc"
Francisco Albert
la source

Réponses:

29

Vous n'obtenez pas ces informations au moment de l' exécution . Ils sont codés en dur dans le compilateur tel qu'il est installé sur votre système.

Ceci est plus évident si vous regardez la définition de compilerNamecomme trouvée dans http://hackage.haskell.org/package/base-4.12.0.0/docs/src/System.Info.html .

compilerName :: String
compilerName = "ghc"

mais même quelque chose comme os

os :: String
os = HOST_OS

est défini en termes d'un nom par ailleurs non défini HOST_OS(une valeur commençant par une lettre majuscule ??), ce qui suggère qu'il ne s'agit que d'un espace réservé qui est remplacé lors de l'installation.

Quelqu'un peut également me corriger (s'il vous plaît!), Mais le {-# LANGUAGE CPP #-}pragma en haut de ce fichier suggère que HOST_OSles éléments similaires sont remplacés par des chaînes appropriées par le préprocesseur C avant la compilation.

chepner
la source
2
Si l'OP en veut vraiment IO, il y a un wrapper uname(3)disponible sur Hackage: hackage.haskell.org/package/bindings-uname
thsutton
19

La question est bonne. La réponse, telle qu'elle est, est que ces valeurs sont statiques par compilation de programme. Ils sont essentiellement compilés dans le programme et ne changent jamais après cela. En tant que tel, rien (dans les hypothèses utilisées par GHC) ne se casse si vous les traitez comme des constantes. Et il est plus pratique d'utiliser une constante simple qu'une action d'E / S.

Mais c'est une sorte de raisonnement hérité. Haskell est une vieille langue. (Non vraiment, il est plus ancien que Java de plusieurs années.) De nombreuses bibliothèques ont été construites avec un raisonnement qui n'est plus considéré comme les meilleures pratiques. Ce sont des exemples de cela. Une bibliothèque moderne les exposant ferait probablement d'eux des actions d'E / S même si les résultats ne changent pas après la compilation. Il est plus utile de placer des choses qui ne sont pas des constantes au niveau source derrière les actions d'E / S, bien qu'il existe encore quelques exceptions notables, comme le Intchangement de taille entre les plates-formes 32 et 64 bits.

En tout cas ... je dirais que vos attentes sont solides, et ces types sont le résultat de bizarreries historiques.

Carl
la source
-9

EDIT: Merci à @interjay et @Antal Spector-Zabusky pour avoir expliqué pourquoi cette réponse est rejetée. Ils ont écrit

La documentation est un peu trompeuse. Les valeurs sont codées en dur dans le compilateur GHC. Après 48 ans, vous savez sûrement que le code réel l'emporte toujours sur la documentation. - interjay hier @ andy256 Vous avez absolument raison de dire que la documentation est mauvaise (en effet, c'est en partie pourquoi Francisco a posé cette question en premier lieu), et votre confusion est compréhensible. La chose à propos de Haskell est que si ces valeurs de chaîne pouvaient varier au moment de l'exécution, ce serait un bug flagrant - les variables ne sont pas autorisées à changer. C'est la signification du constructeur de type IO - il représente un calcul qui est autorisé à accéder au «monde extérieur», et donc dont le résultat peut changer. Faire un appel système est un bon exemple d'une action d'E / S. … [1/2] - Antal Spector-Zabusky Il y a 9 heures @ andy256… (Une autre action d'E / S pourrait être de «mettre à jour un compteur global».) Ainsi, lorsque nous voyons une chaîne, nous savons qu'elle ne peut pas faire de communication avec l'OS sous le capot. C'est pourquoi, peut-être de manière surprenante, si vous n'êtes pas habitué à Haskell, il ne serait pas facile d'implémenter os :: String pour effectuer un appel système - une telle valeur n'est pas implémentable dans Haskell de base, violerait l'attente de chaque programmeur sur la façon dont les programmes travail, et peut-être même déclencher le compilateur et l'optimiseur (pas une préoccupation théorique - il y a des réponses Stack Overflow où les gens rencontrent des problèmes similaires). [2/2] - Antal Spector-Zabusky C'est pourquoi, peut-être de manière surprenante, si vous n'êtes pas habitué à Haskell, il ne serait pas facile d'implémenter os :: String pour effectuer un appel système - une telle valeur n'est pas implémentable dans Haskell de base, violerait l'attente de chaque programmeur sur la façon dont les programmes travail, et peut-être même déclencher le compilateur et l'optimiseur (pas une préoccupation théorique - il y a des réponses Stack Overflow où les gens rencontrent des problèmes similaires). [2/2] - Antal Spector-Zabusky C'est pourquoi, peut-être de manière surprenante, si vous n'êtes pas habitué à Haskell, il ne serait pas facile d'implémenter os :: String pour effectuer un appel système - une telle valeur n'est pas implémentable dans Haskell de base, violerait l'attente de chaque programmeur sur la façon dont les programmes travail, et peut-être même déclencher le compilateur et l'optimiseur (pas une préoccupation théorique - il y a des réponses Stack Overflow où les gens rencontrent des problèmes similaires). [2/2] - Antal Spector-Zabusky et potentiellement même déclencher le compilateur et l'optimiseur (pas une préoccupation théorique - il y a des réponses Stack Overflow où les gens rencontrent des problèmes similaires). [2/2] - Antal Spector-Zabusky et potentiellement même déclencher le compilateur et l'optimiseur (pas une préoccupation théorique - il y a des réponses Stack Overflow où les gens rencontrent des problèmes similaires). [2/2] - Antal Spector-Zabusky

Il dispose actuellement de deux votes de suppression. Je vais laisser ce processus suivre son cours, mais je suggère qu'il a en fait une certaine valeur. D'un côté, leurs explications montrent que la question était faible, tout comme les réponses, car un débutant Haskell pourrait facilement suivre le raisonnement que j'ai fait.

Réponse originale:

Je ne suis pas un programmeur Haskell, mais les deux réponses déjà données ne correspondent pas à la documentation liée par l'OP.

Mon interprétation de la documentation suit.

os :: String - Cela vous donne "Le système d'exploitation sur lequel le programme s'exécute."

Je m'attends à ce que cela émette un appel système pour obtenir les informations. Étant donné que le système sur lequel le programme est compilé peut être différent de celui sur lequel il s'exécute, il ne peut pas s'agir d'une valeur insérée par le compilateur. Si le code est interprété, l'interpréteur peut fournir le résultat, qui doit être obtenu via un appel système.

arch :: String - Cela vous donne "l'architecture de la machine sur laquelle le programme s'exécute."

Encore une fois, je m'attends à ce que cela émette un appel système pour obtenir les informations. Étant donné que le système sur lequel le programme est compilé peut être différent de celui sur lequel il s'exécute, il ne peut pas s'agir d'une valeur insérée par le compilateur.

compilerName :: String - Cela vous donne "L'implémentation Haskell avec laquelle le programme a été compilé ou est en cours d'interprétation."

Cette valeur est certainement insérée par le compilateur / interprète.

compilerVersion :: String- Cela vous donne "La version compilerNameavec laquelle le programme a été compilé ou est en cours d'interprétation."

Cette valeur est certainement insérée par le compilateur / interprète.

Bien que vous puissiez considérer que les deux premiers appels obtiennent une entrée, le résultat provient des valeurs détenues par le système d'exploitation. Les E / S font généralement référence à l'accès au stockage secondaire.

andy256
la source
3
Ce n'est pas vrai pour haskell. Ici, tous les calculs ne sont pas ordonnés et leur résultat peut être mis en cache. Les fonctions sont pures, donc si une fonction n'accepte aucun argument, cela ressemble beaucoup à une constante. Les fonctions d'un argument ressemblent à des hashmaps ou à des dictionnaires, qui calculent la valeur en fonction de la clé. Vous ne pouvez pas utiliser un environnement externe, effectuer des appels système dans de telles fonctions, vous ne pouvez même pas obtenir un nombre aléatoire ou une date actuelle. Mais si vous voulez réellement utiliser ce "séquençage", ou environnement, alors vous devez utiliser la IOmonade pour émuler l'état, émuler la séquence des opérations
Yuri Kovalenko
"Vous ne pouvez pas utiliser un environnement externe, faites des appels système dans de telles fonctions" - Bien sûr que vous le pouvez, surtout si "vous" êtes le compilateur Haskell! Il serait très facile pour une implémentation Haskell de l'implémenter os :: Stringafin qu'elle fasse un appel système lorsqu'elle est évaluée.
Tanner Swett
2
Je ne pense pas que vous compreniez la signification de la monade IO à Haskell.
Sneftel
@Sneftel Vous avez bien sûr raison. J'ai choisi de répondre car après 48 ans de programmation dans tous les paradigmes et d'écriture du compilateur étrange, les réponses initiales ne correspondaient pas à la documentation, et elles ne le sont toujours pas. Il indique clairement que oset archsont obtenus au moment de l'exécution.
andy256
1
La documentation est un peu trompeuse. Les valeurs sont codées en dur dans le compilateur GHC. Après 48 ans, vous savez sûrement que le code réel l'emporte toujours sur la documentation.
interjay