本日はこれの他に、cabal replの件については依存しているcabal-installを更新したりしました
https://twitter.com/igrep/status/1601862213442359297
https://twitter.com/igrep/status/1601862213442359297
Rem m
の (^) :: (Num (Rem m), Integral a) => Rem m -> a -> Rem m
(ただし instance Data.Reflection.Reifies m Word => Num (Rem m)
) を黒魔術で高速化すべく頑張りますRem m
の (^)
が遅かったのです.profをとっていないのでよくわからないのですが, この原因は, Data.Reflection.reflect :: Data.Reflection.Reifies m a => proxy m -> a
で出てくる reflect :: Reifies m Word => proxy m -> Word
の素性が simplifier にから見てよくわからないので,インライン化もされない (*) :: Rem m -> Rem m -> Rem m
の呼び出しが何度も reflect
を呼んで最適化もされない,ということだったっぽいです.そこで, reflect
を (^)
の計算の最初だけ呼び,`(^)` の実装内部においては, (*)
のかわりに,その実装に使われている modulus つき乗法関数(自作) unsafeModMult :: Word -> Word -> Word -> Word
を呼ぶようにする,ということをしたいです.ところが,RULES で (^) を書き換えようとすると type checker が Num (Rem m)
を知ってるくせに Reifies m Word
を知らない,という事態が生じます. そこで Num (Rem m)
だけの制約からmodulusを取ってくる必要に迫られるのですが,`fromInteger :: Integer -> Rem m` が remFromIntegerWithMod modulus
に書き換えられるように実装されていることを利用して RULES で computeModulusFromNumConstraint (remFromIntegerWithMod modulus) = modulus
と書き換える,みたいな真似をしています. これで, AtCoder ABC282-E の実行速度が https://atcoder.jp/contests/abc282/submissions/37366230 (788ms) から https://atcoder.jp/contests/abc282/submissions/37872422 (173ms) へと高速化しました.手書きの剰余冪乗を用いた