「Haskellは競技プログラミングには向いている」と言われたりもするが、競プロやオンラインジャッジにHaskellで取り組もうとすると、最初は問題を解くよりも、「どうやって入力を受けて、出力すれば良いのか?」の方が分からなかったりする。
そんなときのためのメモ。今回は結果の標準出力への出し方。(前編の入力編はこちら)
例
前編で入力を処理可能なところまで変換した。
input.txt
3
10 20
30 40
50 60
sample6.hs
main = do
_ : input <- lines <$> getContents
print . map (map read . words) $ input
-- [[10,20],[30,40],[50,60]]
これを極々単純に各行の和をとって出力、とすると
sample7.hs
main = do
_ : input <- lines <$> getContents
--let ans = map sum . map (map read . words) $ input
let ans = map (sum . map read . words) $ input
-- [30,70,110]
print ans
- 外側のリストの各要素を
sum
するためにmap
する(要は行単位で処理をする関数がsum
の場所にくる) -
map f . map g
はmap (f.g)
なので、このような形になる。 - ここからが本題。出来あがった計算結果のリストを一つづつ改行して出力したい。
sample7.hs
main = do
_ : input <- lines <$> getContents
let result = map (sum . map read . words) $ input
-- [30,70,110]
mapM_ print result
-- 30
-- 70
-- 110
- リスト内の計算結果の出力には専ら
print
を使う print :: Show a => a -> IO ()
-
print
はputStrLn.show
であるのでshow
できる型なら無条件に出力して改行してくれる - printを各要素に適用するには
map
ではなくmapM_
を使う。なぜならばprint
はIOアクションを返すから mapM_ :: (Monad m, Foldable t) => (a -> m b) -> t a -> m ()
- ここで
m
はIO
、t
はリスト、a
はInt
であるので、mapM_
の型は(Int -> IO()) -> [Int] -> IO()
となる
StringOutput.hs
print "OK"
--- "OK"
putStrLn "OK"
-- OK
- ただし、出力する値が
String
の場合print
を使用するとダブルクォーテーションが付いてしまうので、この場合はputStrLn
を使う putStrLn :: String -> IO ()
forM
mapM
と引数の順序が異なるのみで、それ以外は全く同じのforM
。
「すごいHaskellたのしく学ぼう!」では
forM.hs
main = do
colors <- forM [1,2,3,4] $ \a -> do
putStrLn $ "Which color do you associate with the number " ++ show a ++ "?"
getLine
putStrLn "The colors that you associate with 1,2,3 and 4 are: "
mapM putStrLn colors
これはmapM
で書くなら
mapM.hs
main = do
colors <- mapM f [1,2,3,4]
putStrLn "The colors that you associate with 1,2,3 and 4 are: "
mapM putStrLn colors
f :: a -> IO String
f a = do
putStrLn $ "Which color do you associate with the number " ++ show a ++ "?"
getLine
実行結果はいずれも同じ。
result.txt
Which color do you associate with the number 1?
white
Which color do you associate with the number 2?
blue
Which color do you associate with the number 3?
red
Which color do you associate with the number 4?
orange
The colors that you associate with 1, 2, 3 and 4 are:
white
blue
red
orange
「すごいH本」では訳注として「mapM と forM は関数とリスト、どちらの引数を長く書きたいかによって使い分けるのが良いでしょう。」と書かれている。
手続き的に引数に与える値を次々に変えては何かしたい、というようなときにはforM
がしっくりくる場合もある。