読者です 読者をやめる 読者になる 読者になる

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

Haskell

前回の続き

Haskell を使ってみる 2 - kntmr-blog

レンジ

要素の列挙

Prelude> [1..10]
[1,2,3,4,5,6,7,8,9,10]
Prelude> ['a'..'z']
"abcdefghijklmnopqrstuvwxyz"
Prelude> [2,4..10] -- ステップを指定してリストを作成
[2,4,6,8,10]
Prelude> [10,9..1] -- ステップを指定すると減少列の作成が可能
[10,9,8,7,6,5,4,3,2,1]

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

無限リストの作成

Prelude> take 10 [0,5..] -- 最初の10個から構成されるリストを作成
[0,5,10,15,20,25,30,35,40,45]

Haskell は無限リスト全体をすぐに評価することはしない。(遅延評価なので)

Prelude> take 10 (cycle [1,2,3]) -- cycle は与えられたリストの要素を無限に繰り返して無限リストを作成する
[1,2,3,1,2,3,1,2,3,1]
Prelude> take 10 (repeat 'a') -- repeat は与えられた要素を無限に繰り返して無限リストを作成する
"aaaaaaaaaa"
Prelude> replicate 3 "foo" -- replicate は繰り返す回数と要素を指定してリストを作成する
["foo","foo","foo"]

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

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

リスト内包表記

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]

x <- [1..10] で各要素を x に束縛する。| より左はリスト内包表記の出力を表す。| より右には条件を指定できる。(述語と呼ぶ)
述語で要素を間引くことをフィルタと呼ぶ。

Prelude> [x * 2 | x <- [1..10], x * 2 >= 12] -- カンマ区切りで述語を書く
[12,14,16,18,20]

リスト同士の組み合わせ

Prelude> [x + y | x <- [1,2,3], y <- [10,100,1000]] -- 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 関数

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

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

文字列のフィルタ

Prelude> let removeLowercase str = [ch | ch <- str, ch `elem` ['A'..'Z']] -- ['A'..'Z'] に含まれる要素のみフィルタする
Prelude> removeLowercase "Hello World"
"HW"

リスト内包表記の入れ子

Prelude> let xxs = [[1,2,3,4,5],[10,11,12,13,14,15],[20,21,22,23,34,25]]
Prelude> [[x | x <- xs, even x] | xs <- xxs] -- 外側のリスト内包表記の出力部分が別のリスト内包表記になっている。
[[2,4],[10,12,14],[20,22,34]]

xxs の要素(リスト)を xs に束縛して、内側のリスト内包表記に渡す。xs の要素を x に束縛して述語でフィルタして出力する。リスト内包表記の出力は何らかのリストになるので、この場合はリストのリストが全体の結果になる。


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