VSCodeでHaskellプログラムを書こう①:標準入力から値を受け取る

前回の記事

タイトルは初心者向けっぽく、実際に内容は初心者向けなのですが、とにかく手順がややこしいです。
拡張機能としてHaskell関連の一通りの拡張機能とCode-Runnerが入っていることが前提となります。

まず、VSCode上で"Ctrl + ,"を押して、code-runnerを検索します。その中から、Run In Terminalの項目にチェックを入れます。code-runnerでプログラムを実行すると、デフォルトで出力タブに実行されるのですが、出力タブからは標準入力で値を渡すことができないため、ターミナルで実行されるように変更しなければいけません。

とりあえず、ここまでくると実際にプログラムを書く段階に入れます。まずは、"Sample.hs"みたいな適当な名前の新規ファイルを作ります。
今回は標準入力のテストがしたいので、ひとまずAtCoderのPracticeAを解くことを目標としましょう。

プログラムがちゃんとターミナルで実行されるかを確認するために、標準入力から3行受け取って、それをそのまま表示するプログラムを書いてみましょう。

main :: IO()
main = do
    a <- getLine
    bc <- getLine
    s <- getLine
    print $ a ++ " " ++ bc ++ " " ++ s

これを実行してターミナル上で、

10
20 30
hello

と入力すれば、

10 20 30 hello

という出力が得られるはずです。
さて、getLineでは入力された値をString型で受け取るので、10 20 30といった数字ももちろんString型です。なので、String型からInt型に変換しなければ計算ができませんね。
"10 20 30"のような文字列を空白で切り分けるwords関数を使えば、["10" "20" "30"]のように文字列のリストを作ることができます。これに対してmap関数で(read::String -> Int)というread関数による要素ごとの型変換をかければ、[10, 20, 30]のような数値のリストが得られます。

main :: IO()
main = do
    a <- getLine
    bc <- getLine
    s <- getLine
    print $ a ++ " " ++ bc ++ " " ++ s

    let list_abc = words (a ++ " " ++ bc)
    let int_abc = map (read::String -> Int) list_abc
    print $ int_abc

先ほどの標準入力を受け取るコードに3行追加したものです。この処理を1行にまとめて、

let abc = map (read::String -> Int) . words $ (a ++ " " ++ bc)

のように書くことももちろん可能です。これは半角スペースで区切られた文字列のリストに対して、String型->Int型の変換を行う関数なので、別のプログラムにも流用することができます。具体的には、

stoi = map (read :: String -> Int) . words

のように定義しておいて、

let abc = stoi (a ++ " " ++ bc)

のように使うことができます。
さて、問題の解答は、a, b, c の3つの数値の合計と、適当な文字列 s を半角スペースで区切って1行で表示することでしたので、そのようにプログラムを書き足していきます。具体的には、Int型のリストabcに対して、リスト内の合計を算出するsum関数を使います。全体のコードは次のようになります。

main :: IO()
main = do
    a <- getLine
    bc <- getLine
    s <- getLine
    let abc = stoi (a ++ " " ++ bc)
    putStrLn $ show (sum abc) ++ " " ++ s

stoi = map (read :: String -> Int) . words

ちなみにstoi関数を定義する位置は、main関数の前でも後でも構いません。これで問題を解くコードが出来上がりました。


この記事が気に入ったらサポートをしてみませんか?