2011-06-18 7 views
3

、いくつかのスタックオーバーフローの質問への回答でドン・スチュワートによって書かれたコードを取る:ハスケル:なぜメインメソッドのGHCによって推論された型は完全ではありませんか?例えば

import Control.Monad 
import qualified Data.HashTable as H 
import System.Environment 

main = do 
    [size] <- fmap (fmap read) getArgs 
    m <- H.new (==) H.hashInt 
    forM_ [1..size] $ \n -> H.insert m n n 
    v <- H.lookup m 100 
    print v 

はGHCiの中でそれをロードします。

:t getArgs ---> getArgs :: IO [String] 
:t main ---> main :: IO() 

は、なぜメインの型シグネチャはgetArgs :: IO [String]が呼び出されているという事実を反映していませんか?

バイナリを実行するときに引数を付けることができます。 <prog> 145が返されますJust 100 しかし、GHCiでは、次のことはできません。main 145がエラーになります。どのようにGHCiでこのプログラムを実行し、議論をしますか?

答えて

6

mainのタイプは、その最終式のタイプです。 printIO()を生成するので、タイプはmainです。 (>>=)はモナド以外のものを伝播しないため、中間形式は関係ありません。

(>>=) :: Monad m => m a -> (a -> m b) -> m b 

a結果タイプ(m b)に表示されません。

GHCiでプログラムを実行する場合は、:mainコマンドを参照してください。

+0

ありがとうございました。私は* do *が>> =の構文的砂糖であり、その署名が*(>> =)::(Monad m)=> m a - >(a - > m b) - > m b *であることを理解する。しかし、モナド演算を使用する場合でも、型シグネチャが* getArgs :: IO [String] *であるgetArgsが計算で使用されているという事実をコンパイラが利用できないのでしょうか?より意味のあるタイプシグネチャを提供しますか?あるいは、これはまったく不可能なのでしょうか? –

+0

ハスケルではありません。既にそこにあるもの(IO)を超えて、そうすることにどのような価値があるのか​​は分かりません。これは、コンパイラにとって有益な情報ですが、それ以外の情報はありません。あなたが本当に考えていることが、「IO」を分割していない限り、それは物流上の悪夢となる多年にわたる議論の話題です。 – geekosaur

+2

これはあなたのコードを 'mainX :: [String] - > IO()'関数に入れて、 'main = getArgs >> = mainX' –

4

:setにargsの値を設定します。たとえば、次のタイプの署名問題として

Prelude> import System.Environment 
Prelude System.Environment> getArgs 
[] 
Prelude System.Environment> :set args ["foo","bar"] 
Prelude System.Envrionment> getArgs 
["foo","bar"] 

、ここでメインの種類はprint vによって決定されます。それ以前のものはすべて>>演算子で無視されます。

関連する問題