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


25

モジュールで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"

回答:


29

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

あなたがの定義を見ればこれは最も明白であるcompilerNameに見られるようなhttp://hackage.haskell.org/package/base-4.12.0.0/docs/src/System.Info.html

compilerName :: String
compilerName = "ghc"

でも何かのような os

os :: String
os = HOST_OS

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

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


2
OPが本当に必要な場合は、Hackageで利用可能なIOラッパーがuname(3)あります。hackage.haskell.org/ package
uname

19

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

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

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


-9

編集:なぜこの回答が反対投票されているのかを説明してくれた@interjayと@Antal Spector-Zabuskyに感謝します。彼らが書きました

ドキュメントは少し誤解を招くものです。値はGHCコンパイラにハードコードされます。48年後、あなたは確かに実際のコードが常にドキュメンテーションよりも優先されることを知っています。– interjay昨日@ andy256文書が悪いことは確かに正しく(実際、Franciscoが最初にこの質問をした理由の一部です)、あなたの混乱は理解できます。Haskellの重要な点は、これらのString値が実行時に変化する可能性がある場合、それは重大なバグとなるでしょう–変数は変更できません。これがIO型コンストラクタの重要性です。「外界」へのアクセスが許可されている計算を表し、その結果が変わる可能性があります。システムコールの作成は、IOアクションの良い例です。…[1/2] – Antal Spector-Zabusky 9時間前@ andy256…(別のIOアクションは「グローバルカウンターの更新」である可能性があります。)したがって、文字列を表示すると、文字列と通信できないことがわかります。フードの下のOS。そのため、おそらく驚くべきことに、Haskellに慣れていない場合、os :: Stringを実装してシステムコールを実行するのは簡単ではありません。そのような値は、基本的なHaskellでは実装できず、すべてのプログラマーがプログラムをどのように期待するかに違反します。動作し、場合によってはコンパイラとオプティマイザが作動する可能性もあります(理論上の問題ではありません。類似の問題が発生した場合、Stack Overflowの回答があります)。[2/2] –アンタルスペクターザブスキー そのため、おそらく驚くべきことに、Haskellに慣れていない場合、os :: Stringを実装してシステムコールを実行するのは簡単ではありません。そのような値は、基本的なHaskellでは実装できず、すべてのプログラマーがプログラムをどのように期待するかに違反します。動作し、場合によってはコンパイラとオプティマイザが作動する可能性もあります(理論上の問題ではありません。類似の問題が発生した場合、Stack Overflowの回答があります)。[2/2] –アンタルスペクターザブスキー そのため、おそらく驚くべきことに、Haskellに慣れていない場合、os :: Stringを実装してシステムコールを実行するのは簡単ではありません。そのような値は、基本的なHaskellでは実装できず、すべてのプログラマーがプログラムをどのように期待するかに違反します。動作し、場合によってはコンパイラとオプティマイザが作動する可能性もあります(理論上の問題ではありません。類似の問題が発生した場合、Stack Overflowの回答があります)。[2/2] –アンタルスペクターザブスキー コンパイラやオプティマイザが作動する可能性もあります(理論的な問題ではありません。類似の問題が発生した場合、Stack Overflowの回答があります)。[2/2] –アンタルスペクターザブスキー コンパイラやオプティマイザが作動する可能性もあります(理論的な問題ではありません。類似の問題が発生した場合、Stack Overflowの回答があります)。[2/2] –アンタルスペクターザブスキー

現在、2つの削除投票があります。私はそのプロセスがコースを取るようにしますが、それは実際にいくつかの価値があることを示唆しています。余談ですが、Haskellの初心者は私がした推論を簡単にたどることができるので、彼らの説明は質問が弱いことを示しており、答えもそうです。

元の答え:

私はHaskellプログラマではありませんが、すでに与えられた2つの回答は、OPがリンクしたドキュメントと一致しません。

ドキュメントの私の解釈は次のとおりです。

os :: String -これにより、「プログラムが実行されているオペレーティングシステム」が表示されます。

これにより、情報を取得するためのシステムコールが発行されることを期待しています。プログラムがコンパイルされるシステムは、プログラムが実行されるシステムと異なる場合があるため、コンパイラーが挿入する値にすることはできません。コードが解釈されている場合、インタープリターは結果を提供できます。これは、システムコールを介して取得する必要があります。

arch :: String -これにより、「プログラムが実行されているマシンアーキテクチャ」が表示されます。

この場合も、情報を取得するためのシステムコールが発行されることを期待しています。プログラムがコンパイルされるシステムは、プログラムが実行されるシステムと異なる場合があるため、コンパイラーが挿入する値にすることはできません。

compilerName :: String -これにより、「プログラムのコンパイルまたは解釈に使用されたHaskell実装」が得られます。

この値は、コンパイラー/インタープリターによって確実に挿入されます。

compilerVersion :: String-これにより、「compilerNameプログラムがコンパイルされた、または解釈されているバージョン」が表示されます。

この値は、コンパイラー/インタープリターによって確実に挿入されます。

最初の2つの呼び出しは入力を取得していると考えることもできますが、結果はオペレーティングシステムが保持する値から得られます。I / Oは通常、セカンダリストレージアクセスを指します。


3
Haskellには当てはまりません。ここでは、計算は順序付けされておらず、その結果をキャッシュできます。関数は純粋であるため、関数が引数を受け入れない場合は、定数によく似ています。1つの引数の関数は、キーに基づいて値を計算するハッシュマップまたは辞書のように見えます。外部環境を使用したり、そのような関数でsyscallsを実行したりすることはできません。乱数や現在の日付を取得することもできません。しかし、実際にその「シーケンス」または環境を使用したい場合は、IOモナドを使用して状態をエミュレートし、操作のシーケンスをエミュレートする必要があります
Yuri Kovalenko

「外部環境を使用することはできません。そのような関数でsyscallsを実行してください」–特に「あなた」がHaskellコンパイラである場合は特に可能です。os :: String評価時にシステムコールを実行するようにHaskell実装を実装するのは非常に簡単です。
Tanner Swett

2
HaskellのIOモナドの重要性を理解していないと思います。
Sneftel

@Sneftelもちろんです。すべてのパラダイムで48年間プログラミングし、奇妙なコンパイラーを作成した後、最初の回答がドキュメントと一致しなかったため、私は回答することにしました。それははっきり言ってosarch実行時に取得されます。
andy256

1
ドキュメントは少し誤解を招くものです。値はGHCコンパイラにハードコードされます。48年後、実際のコードは常にドキュメントよりも優先されることをご存じでしょう。
interjay
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.