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 を学んで緑色を目指します。