Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

付録B 標準ライブラリリファレンス

prelude(前奏曲)に入っている全 41 個の名前です。import は要りません。どのファイルでも REPL でも、最初から見えています。

いま手元の処理系が何を持っているかは、REPL に聞くのがいちばん確かです。

lune> :env

各項目は「型シグネチャ / 一行の説明 / 例」で、リストを扱うものには無限リストに使えるかを 付けました。Lune ではこれが実用上いちばん効く区別です(第8章)。

表の「無限」列 — ○ は naturalsFrom(1) のような終わりのないリストに使っても 返ってくるもの、× は最後まで辿ろうとして返ってこないものです。この付録の ○× は推測ではなく、実際に無限リストへ適用して確かめた結果です。

型の [T] は型変数(どんな型でもよい)を表します。

B.1 Option — 「あるかもしれない」

名前型意味
Some[T] T -> Option[T]値がある形を作る
NoneOption[T]値がない形
isSome[T] Option[T] -> BoolSome かどうか
isNone[T] Option[T] -> BoolNone かどうか
getOrElse[T] Option[T] -> T -> T中身を取り出す。None なら第2引数
optionMap[T, U] Option[T] -> (T -> U) -> Option[U]中身にだけ関数を適用する
lune> Some(3)
Some(3) : Option[Int]
lune> getOrElse(Some(3), 0)
3 : Int
lune> getOrElse(None, 0)
0 : Int
lune> optionMap(Some(3), fn n: Int -> n * 2)
Some(6) : Option[Int]

Option は第5章、null との使い分けは第7章です。

B.2 Result — 「成功か失敗か」

名前型意味
Ok[T, E] T -> Result[T, E]成功の形を作る
Err[T, E] E -> Result[T, E]失敗の形を作る。中身に理由を入れられる
isOk[T, E] Result[T, E] -> Bool成功かどうか
isErr[T, E] Result[T, E] -> Bool失敗かどうか
unwrapOr[T, E] Result[T, E] -> T -> T成功なら中身、失敗なら第2引数
resultMap[T, U, E] Result[T, E] -> (T -> U) -> Result[U, E]成功のときだけ関数を適用する
lune> Err("boom")
Err("boom") : Result[T, String]
lune> unwrapOr(Ok(3), 0)
3 : Int
lune> unwrapOr(Err("boom"), 0)
0 : Int
lune> resultMap(Ok(3), fn n: Int -> n * 2)
Ok(6) : Result[Int, E]

Option と違い、Err は失敗の理由を運べます。第5章と、第13章の家計簿の例で使います。

B.3 List — 基本

名前型意味無限
NilList[T]空リスト—
Cons[T] T -> List[T] -> List[T]先頭に1つ足す○
head[T] List[T] -> Option[T]先頭。空なら None○
tail[T] List[T] -> Option[List[T]]先頭を除いた残り。空なら None○
isEmpty[T] List[T] -> Bool空かどうか○
lengthAny -> Int要素数(文字列にも使える)×
rangeInt -> Int -> List[Int]range(a, b) は a 以上 b 未満—
map[T, U] List[T] -> (T -> U) -> List[U]各要素に関数を適用する○
filter[T] List[T] -> (T -> Bool) -> List[T]条件を満たす要素だけ残す○
fold[T, U] List[T] -> U -> (U -> T -> U) -> U初期値から畳み込む×
take[T] List[T] -> Int -> List[T]先頭から n 個○
drop[T] List[T] -> Int -> List[T]先頭 n 個を捨てる○
takeWhile[T] List[T] -> (T -> Bool) -> List[T]条件が続く間だけ取る○
dropWhile[T] List[T] -> (T -> Bool) -> List[T]条件が続く間だけ捨てる○
zip[T, U] List[T] -> List[U] -> List[Tuple[T, U]]2本を組にする。短いほうで終わる○
zipWith[T, U, V] List[T] -> List[U] -> (T -> U -> V) -> List[V]組にしながら関数を適用する○
lune> let xs = [1, 2, 3]
ok
lune> head(xs)
Some(1) : Option[Int]
lune> tail(xs)
Some((2 3)) : Option[List[Int]]
lune> range(1, 5)
(1 2 3 4) : List[Int]
lune> map(xs, fn n: Int -> n * 2)
(2 4 6) : List[Int]
lune> filter(xs, fn n: Int -> n % 2 == 1)
(1 3) : List[Int]
lune> fold(xs, 0, fn a: Int n: Int -> a + n)
6 : Int
lune> zip(xs, ["a", "b"])
((1, "a") (2, "b")) : List[Tuple[Int, String]]
lune> zipWith(xs, xs, fn a: Int b: Int -> a * b)
(1 4 9) : List[Int]

length と fold だけが無限リストに使えません。 どちらも「最後まで行く」ことが 仕事だからです。逆に言えば、それ以外は全部安全に使えます — map や filter を 無限リストに掛けても、実際に計算されるのは後で取り出した分だけです(第4章・第8章)。

range は「無限」列が — ですが(リストを受け取らないため)、返すリストは遅延です。 spine は消費された分しか作られないので、take(range(1, 100000000), 5) の代価は take(range(1, 11), 5) と 同じです。幅そのものには代価がありません(4.6節)。

範囲外や空に対しては、例外ではなく素直な値が返ります。

lune> take([1, 2, 3], 10)
(1 2 3) : List[Int]
lune> drop([1, 2, 3], 10)
() : List[Int]
lune> range(5, 1)
() : List[Int]
lune> head(Nil)
None : Option[T]

B.4 List — 終わりのないリストを作る

名前型意味
naturalsFromInt -> List[Int]n, n+1, n+2, … と続く
iterate[T] (T -> T) -> T -> List[T]初期値に関数を繰り返し適用し続ける
repeat[T] T -> List[T]同じ値が続く
cycle[T] List[T] -> List[T]与えたリストを繰り返し続ける
lune> take(naturalsFrom(1), 5)
(1 2 3 4 5) : List[Int]
lune> take(iterate(fn n: Int -> n * 2, 1), 5)
(1 2 4 8 16) : List[Int]
lune> take(repeat("x"), 3)
("x" "x" "x") : List[String]
lune> take(cycle([1, 2]), 5)
(1 2 1 2 1) : List[Int]

この4つはそれ自体が無限なので、必ず take や takeWhile で切って使います。第8章。

B.5 表示と出力

名前型意味
showAny -> String値を Lune の表示形式の文字列にする
printAny -> Unit表示する(改行なし)
printlnAny -> Unit表示して改行する
lune> show(42)
"42" : String
lune> show([1, 2])
"(1 2)" : String
lune> println("hi")
hi
() : Unit

show は文字列を返すだけで、画面には出しません。出すのは print / println です。 show("hi") が "\"hi\"" になるのは、文字列を表示形式にすると引用符が付くためです。

B.6 小さな道具

名前型意味
id[T] T -> T引数をそのまま返す
const[T, U] T -> U -> T第1引数を返し、第2引数は無視する
notBool -> Bool真偽を反転する
lune> id(7)
7 : Int
lune> const(1, 2)
1 : Int
lune> not(true)
false : Bool

const の第2引数は遅延されたまま評価されません。第4章の「使わないものは計算しない」を 1行で確かめられる関数です。

B.7 観察用のビルトイン

遅延評価の挙動を目で見るための道具で、安定した標準 API ではありません (STANDARD_LIBRARY_SPEC.md 8.1 がそう明言しています)。教材とテスト用です。

名前型意味
crash() -> Nothing評価されると実行時エラーになる
tick() -> Int呼ばれるたびに内部カウンタを +1 して返す
tickCount() -> Int現在のカウンタ値。カウンタは増やさない

crash は「評価されなければ何も起きない」ことを示すために使います。tick は 何回評価されたかを数えるためのもので、let が遅延することの証拠になります。

lune> let t1 = tick()
ok
lune> let t2 = tick()
ok
lune> tickCount()
0 : Int

2回 tick() を束縛したのにカウンタが 0 のままです。let は遅延するので、 まだ一度も呼ばれていません。strict let にすると 2 になります。第4章。

B.8 seq と deepForce は関数ではありません

この2つは prelude の関数ではなく、言語の構文です(lazy や force と同じ仲間で、 :env にも出てきません)。

seq a b          # a を評価してから b を返す
deepForce x      # x を中身まで残らず評価する

評価の順序と深さを制御する道具として、第4章 4.7 で扱います。

この付録の出どころ

型シグネチャは REPL の :env(=処理系が持っている実物)から採りました。説明は documents/STANDARD_LIBRARY_SPEC.md に沿っています。「無限」列は、各関数を実際に naturalsFrom(1) へ適用して返ってくるかどうかを確かめた結果です。