Haskellにおける遅延評価でモナドが計算順序を定めることの意味が ようやくにして理解できた. つまり、いくら関数をつないでも渡した引数は必要になるまで評価 してくれない.それが入出力であっても.
import System.IO.Unsafe
getLn :: () -> String
getLn _ = unsafePerformIO getLine
int :: String -> Int
int = unsafePerformIO.readIO
getInt :: () -> Int
getInt () = int$getLn ()
double :: String -> Double
double = unsafePerformIO.readIO
getDouble :: () -> Double
getDouble () = double$getLn ()
unsafePerformIO :: IO a -> a
である.なんて便利なんだ!プロコンでHaskellを使う時の為の テンプレートのつもりで上を書いた. getLn、getDouble は何かしら引数を渡さないといけない関数に するので毎回入力をとる. 初め
getDouble = double $ getLine
としていたから、getDoubleを複数回呼び出しても一行しか入力を 受け取ってくれなかった.
使ってみよう.
main =
let x = getInt ()
y = getInt () in
print (x + y)
便利だ!
main =
let x = getDouble ()
a = getInt () in
print (x ^ a)
たぶんパースエラーを起こす.私のGHCiは、(^)の演算にまず右側を 評価するらしいので、まず getInt を呼び出すらしいのだ. コードを見るとつい x を先に評価してるように思えてしまう.
遅延評価がデフォルトであることの意味がやっと分かった
じゃあどう書くかって言われて、こんなコードくらいしか書けないよ
main = do
s <- getLine
x <- readIO s :: IO Double
t <- getLine
a <- readIO t :: IO Int
print (x^a)
do記法使っときながら (>>=) も使うなら
main = do
x <- getLine >>= readIO :: IO Double
a <- getLine >>= readIO :: IO Int
b <- getLine >>= readIO :: IO Int
print (x^(a+b))
なんかApplicativeとかに<$>だとかでまともに書けるのあった ようなのをなんとなく覚えてる.
ていうか、長いし、
(define-macro (getInt a)
a <- getLine >>= readIO :: Int)
とか書きたくなる