Dlaczego dostęp do System.Info nie jest uważany za operację IO w Haskell?

25

W module System.Infowidzę te funkcje:

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

Dlaczego tam nie IOma? Uzyskują dostęp do systemu ... Czy się mylę? Moje oczekiwania były jak:

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

Przypadek użycia:

      print os            -- "darwin"
      print arch          -- "x86_64"
      print compilerName  -- "ghc"
Francisco Albert
źródło

Odpowiedzi:

29

Nie otrzymujesz tych informacji w czasie wykonywania . Są one zakodowane na stałe w kompilatorze zainstalowanym w systemie.

Jest to najbardziej oczywiste, jeśli spojrzysz na definicję zawartącompilerName w http://hackage.haskell.org/package/base-4.12.0.0/docs/src/System.Info.html .

compilerName :: String
compilerName = "ghc"

ale nawet coś takiego os

os :: String
os = HOST_OS

jest zdefiniowany w kategoriach skądinąd niezdefiniowanej nazwy HOST_OS(wartość zaczynająca się od dużej litery?), co sugeruje, że jest to tylko symbol zastępczy, który jest zastępowany podczas instalacji.

Ktoś też może mnie poprawić (proszę!), Ale {-# LANGUAGE CPP #-}pragma na górze tego pliku sugeruje, że HOST_OSi tym podobne są zastępowane odpowiednimi ciągami przez preprocesor C przed kompilacją.

chepner
źródło
2
Jeśli OP naprawdę chce IOtam być, uname(3)na Hackage jest dostępne opakowanie: hackage.haskell.org/package/bindings-uname
thsutton
19

Pytanie jest dobre. Odpowiedź jest taka, że ​​takie wartości są statyczne na kompilację programu. Zasadniczo są one wkompilowane w program i nigdy potem się nie zmieniają. W związku z tym nic (w założeniach, których używa GHC) nie ulega awarii, jeśli traktuje się je jako stałe. I wygodniej jest użyć prostej stałej niż akcji IO.

Ale to wszelkiego rodzaju starsze rozumowanie. Haskell to stary język. (Nie, tak naprawdę, jest starszy od Java o kilka lat.) Wiele bibliotek zostało zbudowanych z rozumowaniem, które nie jest już uważane za najlepsze praktyki. To są tego przykłady. Nowoczesna biblioteka odsłaniająca je prawdopodobnie sprawiłaby, że stałyby się operacjami IO, nawet jeśli wyniki nie ulegną zmianie po kompilacji. Bardziej przydatne jest umieszczanie rzeczy, które nie są stałymi na poziomie źródłowym, za działaniami We / Wy, chociaż wciąż istnieją pewne znaczące wyjątki, takie jak Intzmiana rozmiaru między platformami 32- i 64-bitowymi.

W każdym razie ... Powiedziałbym, że twoje oczekiwania są solidne, a te typy są wynikiem historycznych osobliwości.

Carl
źródło
-9

EDYCJA: Podziękowania dla @interjay i @Antal Spector-Zabusky za wyjaśnienie, dlaczego ta odpowiedź jest odrzucana. Oni napisali

Dokumentacja jest nieco myląca. Wartości są zakodowane na stałe w kompilatorze GHC. Po 48 latach z pewnością wiesz, że rzeczywisty kod zawsze przebija dokumentację. - interjay wczoraj @ andy256 Masz całkowitą rację, że dokumentacja jest zła (w rzeczy samej, właśnie dlatego Francisco zadał to pytanie), a twoje zamieszanie jest zrozumiałe. Haskell polega na tym, że jeśli wartości String mogą się zmieniać w czasie wykonywania, byłby to poważny błąd - zmienne nie mogą się zmieniać. Takie jest znaczenie konstruktora typu IO - reprezentuje on obliczenia, które mają dostęp do „świata zewnętrznego”, a więc taki, którego wynik może ulec zmianie. Wywołanie systemowe jest dobrym przykładem działania we / wy. … [1/2] - Antal Spector-Zabusky 9 godzin temu @ andy256… (Kolejnym działaniem IO może być „aktualizacja globalnego licznika”.) Kiedy więc widzimy String, wiemy, że nie może on komunikować się z system operacyjny pod maską. To dlatego, być może zaskakujące, jeśli nie jesteś przyzwyczajony do Haskell, nie byłoby łatwo wdrożyć os :: String do wywołania systemowego - żadnej takiej wartości nie da się wprowadzić w podstawowym Haskell, naruszyłby oczekiwania każdego programisty co do tego, jak programy pracować, a nawet potknąć się o kompilator i optymalizator (nie jest to kwestia teoretyczna - istnieją odpowiedzi przepełnienia stosu, w których ludzie napotykają analogiczne problemy). [2/2] - Antal Spector-Zabusky To dlatego, być może zaskakujące, jeśli nie jesteś przyzwyczajony do Haskell, nie byłoby łatwo wdrożyć os :: String do wywołania systemowego - żadnej takiej wartości nie da się wprowadzić w podstawowym Haskell, naruszyłby oczekiwania każdego programisty co do tego, jak programy pracować, a nawet potknąć się o kompilator i optymalizator (nie jest to kwestia teoretyczna - istnieją odpowiedzi przepełnienia stosu, w których ludzie napotykają analogiczne problemy). [2/2] - Antal Spector-Zabusky To dlatego, być może zaskakujące, jeśli nie jesteś przyzwyczajony do Haskell, nie byłoby łatwo wdrożyć os :: String do wywołania systemowego - żadnej takiej wartości nie da się wprowadzić w podstawowym Haskell, naruszyłby oczekiwania każdego programisty co do tego, jak programy pracować, a nawet potknąć się o kompilator i optymalizator (nie jest to kwestia teoretyczna - istnieją odpowiedzi przepełnienia stosu, w których ludzie napotykają analogiczne problemy). [2/2] - Antal Spector-Zabusky i potencjalnie nawet wyzwolić kompilator i optymalizator (nie jest to kwestia teoretyczna - istnieją odpowiedzi przepełnienia stosu, w których ludzie napotykają analogiczne problemy). [2/2] - Antal Spector-Zabusky i potencjalnie nawet wyzwolić kompilator i optymalizator (nie jest to kwestia teoretyczna - istnieją odpowiedzi przepełnienia stosu, w których ludzie napotykają analogiczne problemy). [2/2] - Antal Spector-Zabusky

Obecnie ma dwa głosy usuwania. Pozwolę, aby proces ten przebiegał prawidłowo, ale sugeruję, że ma on pewną wartość. Na marginesie, ich wyjaśnienia pokazują, że pytanie było słabe, podobnie jak odpowiedzi, ponieważ nowicjusz z Haskell mógł łatwo podążać za moim rozumowaniem.

Oryginalna odpowiedź:

Nie jestem programistą Haskell, ale dwie już podane odpowiedzi nie pasują do dokumentacji, którą PO powiązał.

Moja interpretacja dokumentacji jest następująca.

os :: String - To daje „System operacyjny, na którym działa program”.

Oczekuję, że spowoduje to wywołanie systemowe w celu uzyskania informacji. Ponieważ system, na którym kompilowany jest program, może różnić się od tego, na którym działa, nie może być wartością wstawioną przez kompilator. Jeśli kod jest interpretowany, interpreter może dostarczyć wynik, który należy uzyskać za pomocą wywołania systemowego.

arch :: String - To daje „Architekturę maszyny, na której program działa”.

Ponownie spodziewam się, że spowoduje to wywołanie systemowe w celu uzyskania informacji. Ponieważ system, na którym kompilowany jest program, może różnić się od tego, na którym działa, nie może być wartością wstawioną przez kompilator.

compilerName :: String - To daje „implementację Haskell, z którą program został skompilowany lub jest interpretowany”.

Ta wartość jest z pewnością wstawiana przez kompilator / interpreter.

compilerVersion :: String - To daje „wersję compilerName z którą program został skompilowany lub jest interpretowany”.

Ta wartość jest z pewnością wstawiana przez kompilator / interpreter.

Chociaż można wziąć pod uwagę, że pierwsze dwa wywołanie uzyskuje dane wejściowe, wynik pochodzi z wartości przechowywanych przez system operacyjny. I / O ogólnie odnosi się do dodatkowego dostępu do pamięci.

andy256
źródło
3
Nie dotyczy to haskell. Tutaj wszelkie obliczenia są nieuporządkowane, a ich wyniki mogą być buforowane. Funkcje są czyste, więc jeśli funkcja nie przyjmuje żadnych argumentów, jest to bardzo podobne do stałej. Funkcje jednego argumentu wyglądają jak mapy skrótów lub słowniki, które obliczają wartość na podstawie klucza. Nie możesz używać środowiska zewnętrznego, wykonywać wywołań systemowych w takich funkcjach, nie możesz nawet uzyskać losowej liczby lub bieżącej daty. Ale jeśli naprawdę chcesz użyć tego „sekwencjonowania” lub środowiska, musisz użyć IOmonady do emulacji stanu, emulacji sekwencji operacji
Jurij Kowalalenko,
„Nie możesz korzystać ze środowiska zewnętrznego, wykonuj syscall w takich funkcjach” - Jasne, że możesz, zwłaszcza jeśli „ty” jesteś kompilatorem Haskell! Implementacja Haskell byłaby bardzo łatwa w implementacji, aby os :: Stringpodczas oceny wywoływał system.
Tanner Swett
2
Nie sądzę, żebyś rozumiał znaczenie monady IO w Haskell.
Sneftel,
@Sneftel Oczywiście masz rację. Zdecydowałem się odpowiedzieć, ponieważ po 48 latach programowania w każdym paradygmacie i pisaniu dziwnego kompilatora początkowe odpowiedzi nie pasowały do ​​dokumentacji i nadal nie są. Wyraźnie to mówi osi archsą uzyskiwane w czasie wykonywania.
andy256,
1
Dokumentacja jest nieco myląca. Wartości są zakodowane na stałe w kompilatorze GHC. Po 48 latach z pewnością wiesz, że rzeczywisty kod zawsze przebija dokumentację.
interjay