Haskell Advent Calendar 2022 10 日目の記事です。
6 月からHaskell で AtCoder を始めました。まだまだ『灰色』 (レート 400 未満) ですが、そろそろ軌道に乗ったので面白かった点をノートしてみます。
技術的内容は 外部サイト (mdBook) に書いたので、合わせてお楽しみください。
内容は誤りを含む と思いますが、多めに見ていただけるようお願いします 🙇
背景
欲望が合体しました。
- Haskell のモナドを使いこなしてみたい
- ABC でレート 1,200 を取れたら凄い
- 2 つ同時に達成できたら嬉しい
Haskell とは
公式サイト では "An advanced, purely functional programming language" と称していますが、まず構文に目を惹かれます。たとえば:
isPrime :: Int -> Bool
isPrime n
| n <= 1 = False
| n <= 3 = True
| otherwise = loop 2
where
loop i | i >= n = True
| n `mod` i == 0 = False
| otherwise = loop (i + 1)
このくらいなら読めますが、やがて モナド が登場します。モナドが分からなくて、僕は Haskell と疎遠になりました。
AtCoder Beginner Contest (ABC) とは
ABC は毎週開催の『プログラミング・コンテスト』です。問題を解くプログラムを提出します。低速な解答は TLE (実行時間の超過) となって受理されませんから、 計算量の小さなアルゴリズム を考える必要があります。
詳しくは 競技プログラミングことはじめ などをご参照ください。
AtCoder を Haskell で
AtCoder では数学的素養が問われ、 『考察』の比重が『実装』よりも重い と言われています。でも実装がやりたいのです! そこで Haskell を使うことにより、難度を『実装 > 考察』に逆転させます。
Haskell でやる気をハックし、一石二鳥を狙います。
半年後
自分に幻滅していました。
窮地
Haskell はダントツで難しい
Haskell が書けませんでした 。 API ドキュメントが読めず、コンパイルエラーも分かりませんし、 1 問解くのに 6 時間かかったりします。
何かを受信した
苦し紛れに Haskell Weekly Podcast を聞いていると、みんな Nix で環境構築して Coq で検証し、 Haskell で実装している ことに気付きます。壁のシミを眺めながら、自分はナードではなかったと呟くことになりました。
隣人について
AtCoder の Haskell 参加者 (Rated) は僕を含めて 6 ~ 8 人 程度です。身勝手な親近感を覚えます。
隣の Haskell は黒い
誰かの解答を見てみると、 Haskell とは思えない謎のコードを提出、見事 AC (受理) されています。 しかも爆速 ! Tier 3 の言語 で C++ よりも速いのです。 なによ!!
あるいはコンテスト後の提出を見ると、 1 行で問題を解くコードゴルフが何通りも見られます。 Haskell すきーが伝わってくる気がします。例によって黒魔術なので 全く読めません 。
その他 IntMap
担当、 MVector
担当など、解き方にキャラクター性を感じてしまいます。再帰を使う人、 fold
を使う人などの差も見られます。皆かけがえの無い情報源です。
コミュニティの強さ
最近では Haskell で ABC の解説を書いてくれる人がいたり、丁寧に質問に答えて頂いたりと、本当に助かっています。 Haskell に入門し、圧倒的な taker に成り下がろう。
振り返って
Haskell は Rust と似ている?
Rust を知っていると、型クラスや関連型は一撃です。プログラムの書き方もどこか似ている気がします。
とはいえ実際にコードを書くには様々な擦り合わせが必要で、
- 固定長配列が無い
- Or パタンが無い
- 変数名の shadowing が基本非推奨
Iterator
が無い (Stream fusion が起きるため具体的な型を使用すればよい)- 型クラスに静的メソッドが無い (Proxy で『型を渡す』表現はできる)
などの気付きがありました。『無い』ばかりで、有るものには気付いていない気がします。 HKT とか……?
最近は『型族』『データ族』など未知の概念に出会います。モナドの数も増えてきました。 Haskell の本領発揮は、来年の投稿にご期待ください。
久しぶりに Rust を触ると
関数型言語のユーザは『Rust の構文は汚い』とコメントします。僕はそこまで思いませんが、ポイントフリースタイルで高階関数を書きたい気はしました。『至高の言語 Rust』に綻びが見え始めたかもしれません。
ポスト Haskell, ポスト Rust で次に出て来た関数型言語こそが大本命かもしれません。しかし Haskell も大変なものであることは感じられてきましたから、これをやり直す人・作り直す人のバイタリティは計り知れません。遅延評価 (Haskell) でもいいじゃないかという気がしてきました。
良かった本
今度は本の感想で Haskell 入門を掘り下げてみます。
すごいHaskellたのしく学ぼう!
2012 年出版の Haskell 入門書です。巷で『最も簡単』と謳われていますが 十分難しい と思います。
ともあれ競技プログラミングです。 P244 の <$>
演算子を活用すれば、 AtCoder Beginners Selection 第 1 問 が解けるようになります:
module Main (main) where
main :: IO ()
main = do
[a, b] <- map read . words <$> getLine :: IO [Int]
let s = if even (a * b) then "Even" else "Odd"
putStrLn s
以上、成果は『A 問題が解けるようになる』です。 B 問題からは、リストを使うと TLE (時間制限超え) になる危険があります。 AtCoder が始まりました 。
Haskellで戦う競技プログラミング 第2版
さっき読んだ 300 ページは何だったのか……? 梯子を外された気がしますが、課金で解決します。幅を利かせて参りましょう (?) 。
著者ブログ に目次があります。 vector
を抑えれば B 問題が安定し、 モナドで失敗する 気持ちも味わえます。 ついに Haskell が始まりました!
ハイライト
特に嬉しかった情報としては:
PrimMonad
の使い方- Unboxed array の注意点 (タプルは持てない)
- Unboxed vector の注意点
- タプルも持てる (配列 2 本になる!)
- 2 次元配列の持ち方
- タプルも持てる (配列 2 本になる!)
Vector.Generic
と他モジュールの関係- Immutable vector の
modify
関数の使い方とvector-algorithms
の活用
じっくり書いてほしかった内容としては:
Array
の使い方 (Ix
の使い方)State
モナドの使い方- モナドの合成
- データ族について
ところで MVector
には末尾要素の push
がありません。 snoc
は \(O(n)\) の操作です。この本を読んだ後でも、 AtCoder の外では全く戦えないことが伺えます。
Haskell High Performance Programming
今年 1 番面白かった本 になるかもしれません。話の重要度が高過ぎました。
たとえば一時変数が GC を妨げるという恐ろしいエピソードがあります:
> Data.list.foldl' (+) 0 [1..10^6]
500000500000
> let xs = [1..10^6] :: [Int]
> Data.list.foldl' (+) 0 xs
<interactive>: Heap exhausted;
実際は最適化のおかげでエラーになりません。結局、アルゴリズム的な失敗の方が遥かに影響が大きいよと P16 にありました。つまり GHC の自慢話 を浴びただけです。 例が凶悪 過ぎて不安ですよ!
内容は『Haskellで戦う競技プログラミング 第2版』に還元される気がします。読んでも読まなくてもいい感じです。もう少しスローペースで詳しく頼むという場合には良いかもしれません。
競技プログラミングの鉄則
151 問の問題集です。 典型 90 問 が応用力を問うのに対し、本書はアルゴリズムのカバー率を重視しているとか。 著者ブログ から目次を確認できます。
難度設定が絶妙 です。よく自力で完答できますし、解けなくても丁寧な解答・解説が読めます。これでレベルアップできますよ!
『鉄則本』に挑むことは、アルゴリズムのテンプレートプログラムを育てる作業でもあります。競技プログラミングが大好きな『盆栽』作業に変わるわけなので、ある意味ゲームチェンジャーですね。このタイミングで出て来てくれたことに御の字です。
まとめ
Haskell で AtCoder に参加した結果、世の中には面白い人がたくさんいるという希望を見つけました。自分は大して面白くない現実にも気付きました。
特に『ナードな自分』というアイデンティティを失ったのが痛く、代わりに『灰色コーダー』 (プログラミングが下手) という客観的な評価が突きつけられます。
クダを巻いている場合ではありませんでした。テキストエディタを研ぎ澄ますとか、 Haskell でゲームを作るとか。そういった積み重ねの先、今よりも遥かなナードを目指さねばなりません。
もっと遊ぼう!
追伸
さっきの ABC で茶コーダーになっていました。灰色詐欺じゃん……!
図らずも色変記事になりました。次は DP を学んで緑色を目指します。
