Haskell を使ってみる 3 (リスト内包表記)

前回の続き

Haskell を使ってみる 2 (リストの操作) - kntmr-blog

レンジ

列挙できる要素の組み合わせでリストを作成することができる。

Prelude> [1..10]
[1,2,3,4,5,6,7,8,9,10]
Prelude> ['a'..'z']
"abcdefghijklmnopqrstuvwxyz"

ステップを指定してリストを作成することができる。ステップサイズは1つしか指定できないため、等差数列ではないリストは作成できない。

Prelude> [2,4..10] -- 偶数のリスト
[2,4,6,8,10]
Prelude> [10,9..1] -- 減少列の作成が可能
[10,9,8,7,6,5,4,3,2,1]

Prelude> ['a','c'..'z'] -- 文字列のステップ指定
"acegikmoqsuwy"

レンジで上限を指定しない場合、無限リストが作成できる。Haskell は無限リスト全体をすぐに評価することはしない。(遅延評価なので)

Prelude> take 10 [0,5..] -- 無限リストのうち最初の10個の要素で構成されるリストを作成
[0,5,10,15,20,25,30,35,40,45]

cycle は指定されたリストの要素を無限に繰り返して無限リストを作成する。

Prelude> take 10 (cycle [1,2,3]) -- 無限リストのうち最初の10個の要素で構成されるリストを作成
[1,2,3,1,2,3,1,2,3,1]

repeat は指定された要素を無限に繰り返して無限リストを作成する。

Prelude> take 10 (repeat 1) -- 無限リストのうち最初の10個の要素で構成されるリストを作成
[1,1,1,1,1,1,1,1,1,1]

replicate は繰り返す回数と要素を指定してリストを作成する。

Prelude> replicate 5 1
[1,1,1,1,1]

レンジで浮動小数点を扱う場合は精度に注意する。

Prelude> [0.1,0.3..1]
[0.1,0.3,0.5,0.7,0.8999999999999999,1.0999999999999999]

リスト内包表記

[1..10] で生成したリストの各要素の値を x束縛する。| より左はリスト内包表記の出力を表す。

Prelude> take 10 [2,4..] -- 単純なリスト操作
[2,4,6,8,10,12,14,16,18,20]
Prelude> [x * 2 | x <- [1..10]] -- リスト内包表記
[2,4,6,8,10,12,14,16,18,20]

| より右には条件 (述語) を追加できる。述語でリストを間引くことをフィルタと呼ぶ。カンマ区切りで複数の述語を指定したり、複数のリストから値を取り出すことができる。

Prelude> [x * 2 | x <- [1..10], x * 2 > 10] -- 述語を指定
[12,14,16,18,20]
Prelude> [x + y | x <- [1,2,3], y <- [10,100,1000]] -- 複数のリストから値を取り出す
[11,101,1001,12,102,1002,13,103,1003]
Prelude> [x + y | x <- [1,2,3], y <- [10,100,1000], x + y > 100] -- 述語を追加
[101,1001,102,1002,103,1003]

リスト内包表記を使って length 関数を定義する。リストの要素をすべて 1 に置換して sum 関数で足し合わせる。リストから取り出した要素は使わないので _ (アンダースコア) で使い捨てる。

Prelude> length' xs = sum [1 | _ <- xs]
Prelude> length' [1,2,3,4,5]
5
Prelude> length' "Hello"
5

リスト内包表記を使って文字列をフィルタする関数を定義する。

Prelude> removeLowercase str = [c | c <- str, c `elem` ['A'..'Z']]
Prelude> removeLowercase "Hello Haskell"
"HH"

リスト内包表記の入れ子のリストを操作する。外側のリスト内包表記が出力が、別のリスト内包表記になっている。リスト内包表記の出力は何らかのリストになる。

Prelude> let xxs = [[1,2,3,4],[11,12,13,14],[21,22,23,24]]
Prelude> [[x | x <- xs, even x] | xs <- xxs]
[[2,4],[12,14],[22,24]]

今回はリスト内包表記まで。