Clojure

Clojureを学ぶ - シーケンシャルコレクション

Clojureのコレクションは、値を複合的な値に「収集」します。Clojureの主要なコレクション型は4つあります。ベクター、リスト、セット、マップです。これらの4つのコレクション型のうち、ベクターとリストは順序付けられています。

ベクター

ベクターは、インデックス付きのシーケンシャルなデータ構造です。ベクターは、次のように[ ]で表されます。

[1 2 3]

インデックスアクセス

「インデックス付き」とは、ベクターの要素をインデックスで取得できることを意味します。Clojure(Javaと同様)では、インデックスは1ではなく0から始まります。インデックスの要素を取得するには、get関数を使用します。

user=> (get ["abc" false 99] 0)
"abc"
user=> (get ["abc" false 99] 1)
false

無効なインデックスでgetを呼び出すと、nilが返されます。

user=> (get ["abc" false 99] 14)
nil

count

すべてのClojureコレクションはカウントできます。

user=> (count [1 2 3])
3

構築

リテラルの[ ]構文に加えて、Clojureベクターはvector関数で作成できます。

user=> (vector 1 2 3)
[1 2 3]

要素の追加

要素は、conj(conjoinの略)でベクターに追加されます。要素は常にベクターの最後に追加されます。

user=> (conj [1 2 3] 4 5 6)
[1 2 3 4 5 6]

イミュータビリティ

Clojureコレクションは、文字列や数値などの単純な値の重要なプロパティを共有します。たとえば、イミュータビリティや値による等価比較です。

たとえば、ベクターを作成し、conjで変更してみましょう。

user=> (def v [1 2 3])
#'user/v
user=> (conj v 4 5 6)
[1 2 3 4 5 6]

ここで、conjは新しいベクターを返しましたが、元のベクターを調べると、変更されていないことがわかります。

user=> v
[1 2 3]

コレクションを「変更」する関数は、新しいインスタンスを返します。プログラムは、変更されたインスタンスを利用するために、それを記憶するか、渡す必要があります。

リスト

リストはシーケンシャルな連結リストであり、ベクターのように末尾ではなく、リストの先頭に新しい要素を追加します。

構築

リストは最初の要素を関数として呼び出すことで評価されるため、評価を防ぐためにリストを引用符で囲む必要があります。

(def cards '(10 :ace :jack 9))

リストはインデックス化されていないため、firstrestを使用して走査する必要があります。

user=> (first cards)
10
user=> (rest cards)
'(:ace :jack 9)

要素の追加

conjは、ベクターと同様に、リストに要素を追加するために使用できます。ただし、conjは、データ構造に対して一定時間で実行できる場所で常に要素を追加します。リストの場合、要素は先頭に追加されます。

user=> (conj cards :queen)
(:queen 10 :ace :jack 9)

スタックアクセス

リストは、peekとpopを使用してスタックとして使用することもできます。

user=> (def stack '(:a :b))
#'user/stack
user=> (peek stack)
:a
user=> (pop stack)
(:b)