7回目のHaskell

だんだん惰性になってきたけど続けるよ!続けることに意味がある!(マテ
今日のお題は"meansd3"平均と標準偏差を求めます。平均は合計を個数で割った値。標準偏差は分散の平方根で、分散は平均からの距離の2乗の平均。これを展開すると、分散は2乗の平均から平均の2乗を引いた値になります。計算上はこちらの方がやりやすいのでこちらを今回は使います。
[tex:<(-x)^2>]
[tex: = < ^2 - 2x + x^2 >]
[tex: = <^2> - <2x> + ]
[tex: = ^2 - 2^2 + ]
[tex: = -^2]
まあこの方法も数値や母数が大きいと2乗の平均を求める段階でオーバーフローを起こしたりとかいろいろ欠点はあるけどとりあえず今回は目をつぶります(^^;
まあそんなわけでとりあえずは作りました。

main = print( meansd[1,2,3,4] )

meansd ns = divi $ sumTaple ns
    where divi (c,s,s2) = ( s / c, sqrt( s2 / c - (s / c) ** 2)  )

sumTaple []     = ( 0, 0.0, 0.0 )
sumTaple (n:ns) = plusTaple n $ sumTaple ns
    where plusTaple n (c,s,s2) = (c+1, s+n, s2+n*n)

関数名が思いつかなかったのでかなり適当な名前です。気にしないでね。
sumとかlengthとか使えばもっとシンプルになると思いますが今回はあえて再帰で実装しました。というは、ちょっと高速化を意識してみたからです。たとえばただ平均を出すなら以下でよいはず。

average ns = ( sum ns ) / fromIntegral ( length ns )

しかしこれ、sumとlengthで2回再帰処理しちゃうんですよね(たぶん)。その分が遅くなるんじゃないかなと思って一度に再帰処理できるようにタプルで括り出せないかなと思いました。結果、多分再帰処理は1回で済んでいる・・・と思います(自信なし)