List comprehension

Learn Haskell in 10 minutes - HaskellWiki の続き、というか、10分以上かかるので飛ばしたところをやって行こうじゃないかと思うわけですよ。では、早速。

List comprehension

リストの内包表記に関して。

1 Examples

複数のジェネレータを書く場合はカンマで区切る。後に書いたジェネレータの方が先に展開(?)されるようだ。

Prelude> [(i, j) | i <- [1, 2], j <- [1..4]]  
[(1,1),(1,2),(1,3),(1,4),(2,1),(2,2),(2,3),(2,4)]
Prelude> [(i, j) | j <- [1, 2], i <- [1..4]]
[(1,1),(2,1),(3,1),(4,1),(1,2),(2,2),(3,2),(4,2)]
Prelude> 

こ、これが遅延評価ってやつか(知ってたけど)。j が無限なので、i がずっと 1 のまま。

Prelude> take 10 [ (i, j) | i <- [1, 2], j <- [1..]]
[(1,1),(1,2),(1,3),(1,4),(1,5),(1,6),(1,7),(1,8),(1,9),(1,10)]

ネストもできる。

Prelude> take 3 [[(i, j) | i <- [1,2]] | j <- [1..]]
[[(1,1),(2,1)],[(1,2),(2,2)],[(1,3),(2,3)]]

ガード節で True になるものだけを集める。これはクイックソートの例であったな。

Prelude> take 5 [(i,j) | i <-[1..], j <-[1..i-1], gcd i j == 1] 
[(2,1),(3,1),(3,2),(4,1),(4,3)]

アトキンのふるい、っていうアルゴリズムの実装。エラトステネスのふるいは聞いたことあるけど、これは初めて。やることは同じで、素数を見つけるアルゴリズムのようだ。性能はアトキンのふるいの方がいいみたい (Haskell と関係ないな)。何をやっているのかわからない...。

2 List monad

出たモナド。名前は聞いたことあるけど、難しそうなので避けてきた部分。
Haskell の最初のバージョンでは、内包表記は全ての型に対して有効がったけど、今はリストだけ。
1 Examples の例を別の書き方(これがモナド?)にするとこうなるっていう例が出ている。

-- これが
[(i,j) | i <- [1,2], j <- [1..4]]
-- こうなる
do i <- [1,2]
   j <- [1..4]
   return (i,j)

-- これが
[ (i,j) | i <- [1..], let k = i*i, j <- [1..k]]
-- こうなる
do i <- [1..]
   let k = i*i
   j <- [1..k]
   return (i,j)

見た目は命令型言語っぽくなっている。return は | の代わり?ガード節は guard() で囲む?今のところはそれくらいしかいえない。