Applicative論文で見かけたもの その2

本題のApplicativeからはちょっと離れるのですが、ひきつづき、Applicativeの論文で見かけたもののことを書きます。

導入部の例として、行列の転置、Transposeが取り上げられていました。そのインプリメンテーションがかっこいいので思わずうなってしまいました:

転置ですから、このような行列[ [1, 2, 3], [4, 5, 6] ]が:

1, 2, 3
4, 5, 6

こうなる[ [1, 4], [2, 5], [3, 6] ]わけですね...

1, 4
2, 5
3, 6

サンプルにあったコードはこうです…

transpose :: [ [a ] ] -> [ [a ] ]
transpose [ ] = repeat [ ]
transpose (xs : xss) = zipWith (:) xs (transpose xss)

なんとたった2行でやってしまいます。捕捉情報をつけておきましょう。

zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
(:) :: a -> [a] -> [a]
repeat :: a -> [a]

ということなんですが、実際の動きを追ってみると、

transpose [ [1, 2, 3], [4, 5, 6] ] 
      = zipWith (:) [1, 2, 3] (transpose [4, 5 6] )
      = zipWith (:) [1, 2, 3] (zipWith (:) [4, 5, 6] (transpose [ ]) )
      = zipWith (:) [1, 2, 3] (zipWith (:) [4, 5, 6] (repeat [ ]) )
      = zipWith (:) [1, 2, 3] ([ 4 : [ ], 5 : [ ], 6 : [ ] ]
      = zipWith (:) [1, 2, 3] [ [4], [5], [6] ]
      = [1 : [4], 2 : [5], 3 : [6] ]
      = [ [1, 4], [2, 5], [3, 6] ]

ということですね…
repeatは無限リストを作る関数なので、ここでは[ [ ], [ ], … ]という空リストの無限リストを作ってるわけなんですが、この人の長さが無制限なので、transposeが行列のサイズを知る必要がないというところがすごいなーと思ったわけです…
昨日のidにしても、今日のrepeatにしても、最初見たときはここまで便利なものだとはぜんぜん思いませんでした。

ではでは