このコードはGHC7.0.3ではコンパイルされません。
import System.IO
main = do
z <- readLn
print z
私の意図は、stdinから1行を読み取り、それをzに格納して、後でそれを使ってより高度なことを行うことです。エラーメッセージは次のようになります。
test.hs:5:9:
Ambiguous type variable `a0' in the constraints:
(Show a0) arising from a use of `print' at test.hs:5:9-13
(Read a0) arising from a use of `readLn' at test.hs:4:14-19
Probable fix: add a type signature that fixes these type variable(s)
In a stmt of a 'do' expression: print z
In the expression:
do { z <- readLn;
print z;
return () }
In an equation for `main':
main
= do { z <- readLn;
print z;
return () }
明らかに、私がまだ理解していない基本的なことがあります。なぜ機能しないのか、どうすれば修正できるのか説明してください。
EDIT1:print z
をputStrLn z
に変更してコンパイルエラーを修正したので、GHCは文字列を読み取りたいことを理解します。しかし、プログラムを実行すると、理解できないランタイムエラーが発生します。
$ ./test
hello!
test: user error (Prelude.readIO: no parse)
$
「こんにちは!」と入力しました。次に入力します。不安定と見なされるOSXでx86_64GHCを実行していることに注意してください。
EDIT2:readLnをgetLineに変更しましたが、理由もなく魔法のように機能します。理由を知りたいのですが、うまくいきました。
最終コード:
import System.IO
main = do
z <- getLine
print z
タイプとしてreadLn:_Read a => IO a
_。ユーザーから1行を読み取り、文字列をa
型に解析します。タイプa
とは何ですか?それはあなたが望むものです(それがRead
のインスタンスである限り)。例えば:
_readAInt :: IO Int
readAInt = readLn
readABool :: IO Bool
readABool = readLn
_
print
のタイプはShow a => a -> IO ()
です。 Show
のインスタンスである型を取り、それを出力します。たとえば、True
を印刷するには、_print True
_を使用できます。 Int 42を印刷するには、_print 42
_を使用できます。
あなたの例では、printとreadLnを一緒に使用しています。 haskellはreadLn
が返すタイプを理解できないため、これは機能しません。 print
は表示可能な任意の型を取ることができるため、返される型を1つに制限しません。これにより、haskellは型を理解できないため、readLn
の戻り値の型があいまいになります。これはエラーメッセージが言っていることです。
自分のタイプに読み込むのではなく、ユーザーが入力した文字列だけを格納するのはおそらく何でしょう。これは、タイプ_getLine :: IO String
_のgetLineを使用して実行できます。同様に、putStrLn
の代わりにprint
を使用して、文字列を出力することもできます。 putStrLn
のタイプはString -> IO ()
です。
これはあなたがあなたのコードを変更したものですよね?
import System.IO
main = do
z <- readLn
putStrLn z
putStrLn
はString
をstdoutに書き込むため、z
はString
です。したがって、readLn
はstdinからString
を読み取ります。
しかし...readLn
は、stdinからHaskell形式の値を読み取ることを期待しています。つまり、This is a string
のようなものを入力することを期待する代わりに、引用符で囲むことを期待します:"This is a string"
。
修正するには、readLn
をgetLine
に置き換えます。これは、Haskell形式の文字列ではなくリテラルテキストを読み取ります。
import System.IO
main = do
z <- getLine
putStrLn z
readLnは、指定した型を読み戻すため、この方法では使用できません。型を指定する関数で使用する必要があります。一方、getLineは常に文字列を返すため、必要な処理を実行します。
Printの代わりにputStrLnを使用することもできます。 printは引用符を追加します。
したがって、do { z <- getLine; putStrLn z; }
GHCiではあなたが望むことをするべきです。