web-dev-qa-db-ja.com

IO.readLnを使用してHaskellのstdinから読み取る

このコードは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 () }

明らかに、私がまだ理解していない基本的なことがあります。なぜ機能しないのか、どうすれば修正できるのか説明してください。

EDIT1print zputStrLn 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
15
Betamos

タイプとして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 ()です。

27
David Miani

これはあなたがあなたのコードを変更したものですよね?

import System.IO

main = do
    z <- readLn
    putStrLn z

putStrLnStringをstdoutに書き込むため、zStringです。したがって、readLnはstdinからStringを読み取ります。

しかし...readLnは、stdinからHaskell形式の値を読み取ることを期待しています。つまり、This is a stringのようなものを入力することを期待する代わりに、引用符で囲むことを期待します:"This is a string"

修正するには、readLngetLineに置き換えます。これは、Haskell形式の文字列ではなくリテラルテキストを読み取ります。

import System.IO

main = do
    z <- getLine
    putStrLn z
17
dave4420

readLnは、指定した型を読み戻すため、この方法では使用できません。型を指定する関数で使用する必要があります。一方、getLineは常に文字列を返すため、必要な処理を実行します。

Printの代わりにputStrLnを使用することもできます。 printは引用符を追加します。

したがって、do { z <- getLine; putStrLn z; }GHCiではあなたが望むことをするべきです。

10
cge