コンパイル時に型推論が効かない例
下記のように対話的なコードを書いてみました。コンパイルエラーとなりました。
[work06]$ cat test07.hs import System.IO main :: IO () main = do putStrLn "Waht is your name?" a <- readLn putStrLn "How old are you?" b <- readLn return () [work06]$ runghc test07.hs test07.hs:5:16: No instance for (Read t0) arising from a use of `readLn' The type variable `t0' is ambiguous Possible fix: add a type signature that fixes these type variable(s) Note: there are several potential instances: instance Read () -- Defined in `GHC.Read' instance (Read a, Read b) => Read (a, b) -- Defined in `GHC.Read' instance (Read a, Read b, Read c) => Read (a, b, c) -- Defined in `GHC.Read' ...plus 25 others In a stmt of a 'do' block: a <- readLn In the expression: do { putStrLn "Waht is your name?"; a <- readLn; putStrLn "How old are you?"; b <- readLn; .... } In an equation for `main': main = do { putStrLn "Waht is your name?"; a <- readLn; putStrLn "How old are you?"; .... } test07.hs:7:16: No instance for (Read t1) arising from a use of `readLn' The type variable `t1' is ambiguous Possible fix: add a type signature that fixes these type variable(s) Note: there are several potential instances: instance Read () -- Defined in `GHC.Read' instance (Read a, Read b) => Read (a, b) -- Defined in `GHC.Read' instance (Read a, Read b, Read c) => Read (a, b, c) -- Defined in `GHC.Read' ...plus 25 others In a stmt of a 'do' block: b <- readLn In the expression: do { putStrLn "Waht is your name?"; a <- readLn; putStrLn "How old are you?"; b <- readLn; .... } In an equation for `main': main = do { putStrLn "Waht is your name?"; a <- readLn; putStrLn "How old are you?"; .... }
ambiguousと出てきたので、明示的に型を指定する必要があります。
readLn :: Read a => IO a
なので、IO Stringを追加しました。これを試したところ、コンパイルは通るが、実行時エラーとなってしまいました。
[work06]$ cat test08.hs import System.IO main :: IO () main = do putStrLn "Waht is your name?" a <- readLn :: IO String putStrLn "How old are you?" b <- readLn :: IO String return () [work06]$ runghc test08.hs Waht is your name? foo bar test08.hs: user error (Prelude.readIO: no parse)
エラーメッセージを調べてみると、次の情報がありました。 http://stackoverflow.com/questions/7801407/read-from-stdin-in-haskell-using-io-readln 型があってないとのことのようです。
原因が分からず、しばし悩みました。基本に立ち返り、
readLn :: Read a => IO a
なのだから、
Read String => IO String
となるはずです。
Readのインスタンスをみたところ、
http://hackage.haskell.org/package/base-4.7.0.0/docs/Prelude.html#t:Read
Read Charはあっても、Read Stringはありませんでした。
ちょっと疑問に思ったのは、なんでコンパイル時にエラーにならないのかという点です。推測になりますが、Read aのaは実行時にならないと判明しないからなのかもしれません。
getLineの型はIO Stringなので、期待した通りに動きました。
[work06]$ cat test09.hs import System.IO main :: IO () main = do putStrLn "Waht is your name?" a <- getLine putStrLn "How old are you?" b <- getLine return () [work06]$ runghc test09.hs Waht is your name? foo bar How old are you? 30