あるこんなブログの記事 「HaskellとOCamlの速度を比較してみた」(http://d.hatena.ne.jp/hideshi_o/touch/20120823/1345732820) 言語別の速度比較をしているのだけど、それぞれの言語についてただとにかく 速いものに洗練した結果同士を比べることになる.その洗練する作業はどこかで 打ち切らないといけないのだけれど.コメントがちょっとイラッと来た. 以下のコードをそれぞれ -O2 オプション付きでghcコンパイルして、それぞれ 一度ずつ速度を測ってみた.import Data.List main = print $ maximum $ filter (\x -> reverse(show x) == show x) $ [x*y | x <- [100 .. 999], y <- [x .. 999]] -- real: 0.748000 sec. -- user: 0.639604 sec. -- kernel: 0.000000 sec.
記事の中で最終的に「追記2」として使われてたコード、大体そのまま. よくわからないけど、999*999 以下の整数で回文数となってるものの 内最大のものを計算して出力するプログラムということだろう.だから 下限は実際問題ではないのだけど. show は任意の型のものを文字列にする関数. 任意の型を受け付けるだなんて、普通のhaskellで書く関数とは 意味が違うだろうから、あんまり使いたくない.show自体にかかる 計算時間もバカにできないんじゃないか. (int x) が回文数であるか判定する述語として(reverse(show x))==(show x)
を使っていて、よくわからないからこれでいいけど、(show x)は一度 計算したら変数にもっておこう.import Data.List main = print $ maximum $ filter (\x -> let s = show x in reverse s == s) $ [x*y | x <- [100 .. 999], y <- [x .. 999]] -- real: 0.499000 sec. -- user: 0.405603 sec. -- kernel: 0.000000 sec.
show の使用回数は一度に留められる. 内包表記で書いたリストに対して直接filterをしているけれど、 内包表記ってのはそもそも次のような書き方をするためのものだろう.import Data.List main = print $ maximum $ [x*y | x <- [100 .. 999], y <- [x .. 999], let s = show $ x * y in reverse s == s] -- real: 0.327000 sec. -- user: 0.265202 sec. -- kernel: 0.015600 sec.
地味に少し速くなっている. さっき別のlinux機でfilter版と内包表記に含める版との差はほとんど 無かったのだけれど. 私が上をコメントに書いたら、筆者でもない誰かが私のコードを含めた ものをまとめとか勝手に言って書いてたけど、let束縛をlet文にしてた.import Data.List main = print $ maximum $ [z | x <- [100 .. 999], y <- [x .. 999], let z = x * y, let s = show z, reverse s == s] -- real: 0.468000 sec. -- user: 0.390002 sec. -- kernel: 0.031200 sec.
手続き型言語的な脳で考えると、letは少しスコープの広い変数を 定義してるようなものだから、しかも2つもやってると時間が余計に かかりそうだ.正直嫌だ.
コメ(0) | トラ(0)