📖

Elmで競技プログラミング(AtCoder)を解いてみよう!(簡単に始められる環境アリ!)

2021/04/01に公開

皆さんはプログラミング言語を学びはじめのときはどんなふうに勉強をしていますか? いろんな勉強方法があるとは思いますが、競技プログラミングで問題を解くことで言語の書き味を確かめて行くのが効率の良い勉強方法の一つとして挙げられると思います。中でも有名な競技プログラミングのコンテストサイトがAtCoderになります。

それでは早速問題を解いてElmで言語提出・・・あれ? 無い・・・😇 そうです。ElmはWEB開発に特化した言語のため競技プログラミングサービスではサポートされていないのでした・・・。

しかし、安心してください!ElmはAltJSな言語なので、コンパイルすることでJavaScript(Node.js)として提出が可能なのです!色々小細工する必要があるのですが、なんとすぐに競技プログラミングが始められる環境を用意しておきました。

こちらがElmによる競技プログラミング環境になります。

使い方

使い方はREADMEに載っているのでこちらを御覧ください。

実際解いてみた

実際にどのように解けるのかということで、AtCoder Beginner Contestの74回目のA問題を解いてみました。

この問題は以下の制約で、2行の入力が渡されます。

この入力はList Stringとして表現されます。つまり、以下のような入力の場合、["3", "4"]このような文字列のリストとして表現されます。

3
4

計算においては文字列ではなく数字として受け取りたいため、Listに対してString.toIntを適用します。この結果は、[Just 3, Just 4]となります。あれ? Justとはなんだろうか? ElmではMaybe型と呼ばれる失敗するかもしれない計算を扱うための型が用意されています。成功した場合は、Just n、失敗した場合は、Nothingとなります。今回は成功した値だけを取り出したいため、List.filterMapを適用します。すると、望み通り、[3, 4]が取り出すことができます。

Listの先頭2つの要素を取りたい。このようなときは、パターンマッチを用います。空の[]はリストの末尾を表し、n :: a :: [] == 3 :: 4 :: [] のように値を取り出す事ができます。この問題では、N x Nのマス目のうち、Aマス白く塗ったとき、黒いマス(残りのマス)は何マスになるか?と言う問題なので、引き算をしてあげます。最後は、String.fromIntで文字列に変換してあげれば結果を出力することが可能になります。

solveA : List String -> String
solveA inputs =
    case List.filterMap String.toInt inputs of
        n :: a :: [] ->
            String.fromInt <| n * n - a

        _ ->
            "fail"

もう少し高度なB問題をサンプルで解いているのでそちらも参照してみてください。

工夫した点

なるべくトライアンドエラーのサイクルを早くしたいので、ビルド速度が早いと噂のesbuildを採用してみました。本当に早いです。

CLI用に特化したElmの書き方として、workerという仕組みを用いています。elm-testもこの仕組を使っているようです。

次の課題

もっとトライアンドエラーがしやすいように、テストコードを用意する予定です。実行して確認、よりもテストコードでテストして通す方が一気に複数ケース試せますし、関数型ぽい気がします。また、関数型プログラミングに慣れないという型のためにいろんな問題を解いて、解説した記事が上がると嬉しいのかなと思います(私は競技プログラミングは苦手なので、どなたか!)。

まとめ

Elmでも競技プログラミングは出来まぁす!(今回載せていませんが、そこそこ遅いNode.jsぐらいな実行速度でした)

Discussion