0 filledなN進数とListモナド上のmapM

Excess3の話.まぁ,endlessの問題で過去にも同じネタ使ってはいるが.

割と使うくせにHaksellだと微妙に長くてgolfに困る0 filled N進数への変換.もしOctalやHexadecimalなら,

import Text.Printf;printf"%08X"n

とかで済むところだろうが.一応NumericにshowIntAtBaseもあるが,これは0 filledにならないので,一度大きな桁を足してから変換した後に最上位だけ削るとかすることになる.どっちにしろimportが高コストなので避けていきたい.

こんな状況,あまり大きくない数であればmapMが短縮力を持つ.mapMは,

mapM :: Monad m => (a -> m b) -> [a] -> m [b]
mapM f as = foldr (mcons . f) (return [])
    where mcons p q = p >>= \x -> q >>= \y -> return (x:y)

なので,Listモナドの場合こういう書き方ができる.

mapM(\_->"01")[1..3]
["000","001","010","011","100","101","110","111"]
mapM(\_->"012")[1,2]
["00","01","02","10","11","12","20","21","22"]

どうみても0 filled N進数です.なので,8桁2進数とかならシンプルに

mapM(\_->"01")[1..8]!!n

でいいことになる.

これの特によいところはN進数エンコードされた(あるいはしておいた)データをデコードしてお絵かきをするような場合,"01"のところを" *"やら" X"やらにするだけで一旦数字を介すようなことなくいきなり欲しいものに変換したりもできるというあたりか.数字が大きいともちろん遅いのでtimeout注意.