web-dev-qa-db-ja.com

System.InfoへのアクセスがHaskellのIO操作と見なされないのはなぜですか?

モジュール内 System.Info これらの関数が表示されます。

os :: String
Arch :: String
compilerName :: String
compilerVersion :: Version

なぜIOがないのですか?彼らはシステムにアクセスしています...私は間違っていますか?私の期待は次のようなものでした:

os :: IO String
Arch :: IO String
compilerName :: IO String
compilerVersion :: IO Version

使用事例:

      print os            -- "darwin"
      print Arch          -- "x86_64"
      print compilerName  -- "ghc"
25

runtimeでその情報を取得していません。これらは、システムにインストールされているとおりにコンパイラーでハードコーディングされます。

http://hackage.haskell.org/package/base-4.12.0.0/docs/src/System.InfoにあるcompilerNameの定義を見ると、これは最も明白です。 html

compilerName :: String
compilerName = "ghc"

osのようなものでも

os :: String
os = Host_OS

それ以外は未定義の名前で定義されているHost_OS(大文字で始まる値??)これは、インストール中に置き換えられる単なるプレースホルダーであることを示唆しています。

誰かが私を訂正することもできます(お願い!)が、{-# LANGUAGE CPP #-}そのファイルの先頭にあるプラグマは、Host_OSなどは、コンパイル前にCプリプロセッサによって適切な文字列に置き換えられます。

29
chepner

質問は良いものです。そのような答えは、それらの値はプログラムのコンパイルごとに静的であるということです。これらは基本的にプログラムにコンパイルされ、その後変更されることはありません。そのため、それらを定数として処理しても、(GHCが使用する仮定では)何も壊れません。また、IOアクションよりも単純な定数を使用する方が便利です。

しかし、それはあらゆる種類の従来の推論です。 Haskellは古い言語です。 (実際には、それはJavaより数年前のものです。)多くのライブラリは、もはやベストプラクティスとは見なされない理由で構築されています。これらはその例です。それらを公開する最新のライブラリは、コンパイル後に結果が変化しない場合でも、おそらくそれらをIOアクションにします。ソースレベルで定数ではないものをIOアクションの後ろに置くと、さらに便利です。ただし、32ビットプラットフォームと64ビットプラットフォーム間でIntのサイズを変更するなど、いくつかの注目すべき例外があります。

いずれにせよ...あなたの期待は確かであり、それらのタイプは歴史的な奇妙さの結果です。

19
Carl