Warum wird der Zugriff auf System.Info in Haskell nicht als E / A-Vorgang angesehen?

25

Im Modul System.Infosehe ich folgende Funktionen:

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

Warum gibt es dort keine IO? Sie greifen auf das System zu ... irre ich mich? Meine Erwartung war ungefähr so:

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

Anwendungsfall:

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

Antworten:

29

Sie erhalten diese Informationen zur Laufzeit nicht . Sie sind im Compiler fest codiert, wie auf Ihrem System installiert.

Dies ist am offensichtlichsten, wenn Sie sich die Definition compilerNameunter http://hackage.haskell.org/package/base-4.12.0.0/docs/src/System.Info.html ansehen .

compilerName :: String
compilerName = "ghc"

aber auch so etwas os

os :: String
os = HOST_OS

wird als ansonsten undefinierter Name definiert HOST_OS(ein Wert, der mit einem Großbuchstaben beginnt ??), was darauf hindeutet, dass es sich nur um einen Platzhalter handelt, der während der Installation ersetzt wird.

Jemand kann mich auch korrigieren (bitte!), Aber das {-# LANGUAGE CPP #-}Pragma oben in dieser Datei legt nahe, dass HOST_OSund dergleichen vor dem Kompilieren vom C-Präprozessor durch entsprechende Zeichenfolgen ersetzt werden.

chepner
quelle
2
Wenn das OP wirklich etwas drin haben will IO, gibt uname(3)es auf Hackage einen Wrapper : hackage.haskell.org/package/bindings-uname
thsutton
19

Die Frage ist gut. Die Antwort ist, wie es ist, dass diese Werte pro Programmkompilierung statisch sind. Sie werden im Wesentlichen in das Programm kompiliert und ändern sich danach nie mehr. Als solches bricht nichts (in den von GHC verwendeten Annahmen), wenn Sie sie als Konstanten behandeln. Und es ist bequemer, eine einfache Konstante als eine E / A-Aktion zu verwenden.

Aber das ist alles eine Art Legacy-Argumentation. Haskell ist eine alte Sprache. (Nein, es ist einige Jahre älter als Java.) Viele Bibliotheken wurden mit Argumenten erstellt, die nicht mehr als Best Practices gelten. Dies sind Beispiele dafür. Eine moderne Bibliothek, die sie verfügbar macht, würde sie wahrscheinlich zu E / A-Aktionen machen, obwohl sich die Ergebnisse nach der Kompilierung nicht ändern. Es ist nützlicher, Dinge, die keine Konstanten sind, auf der Quellenebene hinter E / A-Aktionen zu setzen, obwohl es immer noch einige bemerkenswerte Ausnahmen gibt, wie das IntÄndern der Größe zwischen 32- und 64-Bit-Plattformen.

Auf jeden Fall ... Ich würde sagen, Ihre Erwartungen sind solide und diese Typen sind das Ergebnis historischer Kuriositäten.

Carl
quelle
-9

EDIT: Vielen Dank an @interjay und @Antal Spector-Zabusky für die Erklärung, warum diese Antwort abgelehnt wird. Sie schrieben

Die Dokumentation ist etwas irreführend. Die Werte sind im GHC-Compiler fest codiert. Nach 48 Jahren wissen Sie sicher, dass der eigentliche Code immer die Dokumentation übertrifft. - interjay gestern @ andy256 Sie haben absolut Recht, dass die Dokumentation schlecht ist (in der Tat, deshalb hat Francisco diese Frage überhaupt gestellt), und Ihre Verwirrung ist verständlich. Die Sache mit Haskell ist, dass wenn diese String-Werte zur Laufzeit variieren könnten, dies ein ungeheurer Fehler wäre - Variablen dürfen sich nicht ändern. Dies ist die Bedeutung des IO-Typkonstruktors - er stellt eine Berechnung dar, die auf die "Außenwelt" zugreifen darf und deren Ergebnis sich ändern kann. Ein Systemaufruf ist ein gutes Beispiel für eine E / A-Aktion. … [1/2] - Antal Spector-Zabusky vor 9 Stunden @ andy256… (Eine weitere E / A-Aktion könnte darin bestehen, einen globalen Zähler zu aktualisieren.) Wenn wir also einen String sehen, wissen wir, dass keine Kommunikation mit ihm möglich ist das Betriebssystem unter der Haube. Dies ist der Grund, warum es, vielleicht überraschend, wenn Sie nicht an Haskell gewöhnt sind, nicht einfach wäre, os :: String für einen Systemaufruf zu implementieren - ein solcher Wert ist in Haskell nicht implementierbar und würde die Erwartung jedes Programmierers verletzen, wie Programme ausgeführt werden arbeiten und möglicherweise sogar den Compiler und den Optimierer auslösen (kein theoretisches Problem - es gibt Stack Overflow-Antworten, bei denen Menschen auf analoge Probleme stoßen). [2/2] - Antal Spector-Zabusky Dies ist der Grund, warum es, vielleicht überraschend, wenn Sie nicht an Haskell gewöhnt sind, nicht einfach wäre, os :: String für einen Systemaufruf zu implementieren - ein solcher Wert ist in Haskell nicht implementierbar und würde die Erwartung jedes Programmierers verletzen, wie Programme ausgeführt werden arbeiten und möglicherweise sogar den Compiler und den Optimierer auslösen (kein theoretisches Problem - es gibt Stack Overflow-Antworten, bei denen Menschen auf analoge Probleme stoßen). [2/2] - Antal Spector-Zabusky Dies ist der Grund, warum es, vielleicht überraschend, wenn Sie nicht an Haskell gewöhnt sind, nicht einfach wäre, os :: String für einen Systemaufruf zu implementieren - ein solcher Wert ist in Haskell nicht implementierbar und würde die Erwartung jedes Programmierers verletzen, wie Programme ausgeführt werden arbeiten und möglicherweise sogar den Compiler und den Optimierer auslösen (kein theoretisches Problem - es gibt Stack Overflow-Antworten, bei denen Menschen auf analoge Probleme stoßen). [2/2] - Antal Spector-Zabusky und möglicherweise sogar den Compiler und den Optimierer auslösen (kein theoretisches Problem - es gibt Stack Overflow-Antworten, bei denen Menschen auf analoge Probleme stoßen). [2/2] - Antal Spector-Zabusky und möglicherweise sogar den Compiler und den Optimierer auslösen (kein theoretisches Problem - es gibt Stack Overflow-Antworten, bei denen Menschen auf analoge Probleme stoßen). [2/2] - Antal Spector-Zabusky

Es hat derzeit zwei Löschstimmen. Ich werde diesen Prozess seinen Lauf nehmen lassen, aber vorschlagen, dass er tatsächlich einen gewissen Wert hat. Nebenbei bemerkt, ihre Erklärungen zeigen, dass die Frage schwach war, ebenso wie die Antworten, da ein Haskell-Neuling leicht der Argumentation folgen konnte, die ich gemacht habe.

Ursprüngliche Antwort:

Ich bin kein Haskell-Programmierer, aber die beiden bereits gegebenen Antworten stimmen nicht mit der Dokumentation überein, die das OP verknüpft hat.

Meine Interpretation der Dokumentation folgt.

os :: String - Dies gibt Ihnen "Das Betriebssystem, auf dem das Programm ausgeführt wird."

Ich gehe davon aus, dass dies einen Systemaufruf auslöst, um die Informationen zu erhalten. Da sich das System, auf dem das Programm kompiliert wird, möglicherweise von dem unterscheidet, auf dem es ausgeführt wird, kann es kein vom Compiler eingefügter Wert sein. Wenn der Code interpretiert wird, kann der Interpreter das Ergebnis bereitstellen, das über einen Systemaufruf abgerufen werden muss.

arch :: String - Dies gibt Ihnen "Die Maschinenarchitektur, auf der das Programm ausgeführt wird."

Auch hier erwarte ich, dass dies einen Systemaufruf auslöst, um die Informationen zu erhalten. Da sich das System, auf dem das Programm kompiliert wird, möglicherweise von dem unterscheidet, auf dem es ausgeführt wird, kann es kein vom Compiler eingefügter Wert sein.

compilerName :: String - Dies gibt Ihnen "Die Haskell-Implementierung, mit der das Programm kompiliert wurde oder interpretiert wird."

Dieser Wert wird sicherlich vom Compiler / Interpreter eingefügt.

compilerVersion :: String- Dies gibt Ihnen "Die Version, compilerNamemit der das Programm kompiliert wurde oder interpretiert wird."

Dieser Wert wird sicherlich vom Compiler / Interpreter eingefügt.

Während Sie möglicherweise davon ausgehen, dass die ersten beiden Aufrufe Eingaben erhalten, stammen die Ergebnisse aus Werten, die vom Betriebssystem gehalten werden. E / A bezieht sich im Allgemeinen auf den sekundären Speicherzugriff.

andy256
quelle
3
Es ist nicht wahr für Haskell. Hier sind alle Berechnungen ungeordnet und ihr Ergebnis kann zwischengespeichert werden. Funktionen sind rein. Wenn also eine Funktion keine Argumente akzeptiert, ähnelt sie einer Konstanten. Funktionen eines Arguments sehen aus wie Hashmaps oder Wörterbücher, die den Wert basierend auf dem Schlüssel berechnen. Sie können keine externe Umgebung verwenden, in solchen Funktionen Systemaufrufe ausführen und nicht einmal eine Zufallszahl oder ein aktuelles Datum erhalten. Aber wenn Sie tatsächlich diese "Sequenzierung" oder Umgebung verwenden möchten, müssen Sie IOMonade verwenden, um den Zustand zu emulieren, die Sequenz von Operationen zu emulieren
Yuri Kovalenko
"Sie können keine externe Umgebung verwenden, Syscalls in solchen Funktionen ausführen" - Sicher können Sie dies, insbesondere wenn "Sie" der Haskell-Compiler sind! Es wäre für eine Haskell-Implementierung sehr einfach os :: String, sie so zu implementieren , dass sie bei der Auswertung einen Systemaufruf ausführt.
Tanner Swett
2
Ich glaube nicht, dass Sie die Bedeutung der IO-Monade in Haskell verstehen.
Sneftel
@Sneftel Du bist natürlich richtig. Ich habe mich für eine Antwort entschieden, weil nach 48 Jahren Programmierung in jedem Paradigma und Schreiben des ungeraden Compilers die ersten Antworten nicht mit der Dokumentation übereinstimmten und immer noch nicht. Es sagt klar, dass osund archwerden zur Laufzeit erhalten.
andy256
1
Die Dokumentation ist etwas irreführend. Die Werte werden im GHC-Compiler fest codiert. Nach 48 Jahren wissen Sie sicher, dass der eigentliche Code immer die Dokumentation übertrifft.
Interjay