これは「SATySFi Advent Calendar 2019」の17日目の記事です。
16日目はbd_gfngfnさんでした。18日目はmonaqaさんです。
はじめに
この記事ではSATySFiのoption型について解説します。
対象はSATySFiの初心者ですが、The SATySFibookを読み終わっていることを仮定します。
option引数の使いどころ
option型は答えが無いときがあるときによく使われます。
答えが無いときとは、例えば「リストの先頭を取り出す関数に空リストを与えた時」など、回復不能で致命的なエラーではないが適切な値を設定できないときのことです。
こんなものを使えてどう嬉しいかと疑問になるかもしれませんが、適切な値がわからなかったときに安易にエラーを返すと、単純になる代わりにすぐにエラーが出てなかなかコンパイルできないパッケージ・文書ができてしまいます。
また、関数の型から失敗する可能性のある操作を行う関数であるということがすぐにわかることも魅力の一つです。
失敗する可能性があることがわかればそれについて事前に初期値を用意しておくなどの対応が可能になります。
option型を返す関数は多くの場所で定義されており、satysfi-baseのlist-extパッケージではなんと14個も定義されています。
使えると非常に便利で汎用性も高まるのでぜひマスターしましょう。
option型の中身
option型はint option
やstring option
などのように型名 option
という形をしており、どんな型(ユーザーが独自に定義した型であっても)にでも対応できます。
さて、この万能感あふれるoption型はこのような形をしています(実際は内部で定義されているのですが、もしパッケージの形で実装するならこうなるでしょう)。
type 'a option = None | Some('a)
何もないことを表すNone
とそれ以外の場合の値を保持するSome(v)
という二通りだけです。単純ですね。
例えば、さきほど例で出した「リストの先頭を取り出す関数(head
)」に値を与えてみて結果を見てみましょう。
head [1;2;3;4]
=> Some(1)
head [`1`;`2`;`3`]
=> Some(`1`)
head []
=> None
なんとなくわかってきたと思います。
option型の中身の取り出し方
さて、このままではSome(v)
という形で囲われてしまっていてそのままでは単純な足し算すらできません。なのでこの中身のv
を取り出すことにしましょう。
しかし、単純に取り出そうとしてもその値がNone
である時のことも考慮しないといけません。そこで、ここで「パターンマッチ」という構文を使います。
詳しくはThe SATySFibookの46ページを読んで欲しいのですが、
match expr with
| pattern_1 -> expr_1
| pattern_2 -> expr_2
.
.
.
| pattern_n -> expr_n
という風にして値などの中身に応じて処理を変えることができる便利機能です。
例えば、「1のときには`1`
を、2のときには`2`
を、それ以外では`n`
を返す関数」は
let f n =
match n with
| 1 -> `1`
| 2 -> `2`
| _ -> `n`
と書けます。ここで最期に使っている_
はワイルドカードと呼ばれる「それ以外全てのとき」を表せるパターンです。
if文でも書けるような内容ですが、複数の場合を書き分けるときに重宝します。
さて、これを使ってoptionの中身を取り出しますが、これは単純に、
match opt with
| Some(v) -> v_1
| None -> v_2
というようにしてSome(v)
のときとNone
のときで場合分けをするだけです。
さて、「head
関数でint list
の先頭を取り出すが、もし空リスト出会ったら0
を返す」という関数f
を定義しようとするとどうなるでしょう。
答えはこうなります。
let f lst =
match head lst with
| Some(n) -> n
| None -> 0
option型を扱うための関数
標準ライブラリに含まれているopiton.satygファイルで以下の3つの関数が提供されています(モジュール名はOption
)。
-
map : ('a -> 'b) -> 'a option -> 'b option
-
from : 'a -> 'a option -> 'a
-
bind : 'a option -> ('a -> 'b option) -> 'b option
-
map
関数は中身がNone
のときはそのままNone
を返し、Some(v)
だったときはv
に対して最初に受け取っていた関数を適用します。 -
from
は中身がNone
だったときには最初に受け取っていた初期値を返し、Some(v)
だったときにはそのv
を返す関数です。 -
bind
はmap
関数とほとんど同じですが、受け取る関数自体もoption型を返します。
標準ライブラリ以外にもsatysfi-baseのoption-extパッケージでも多くの関数が用意されています。
おわりに
option型の扱い方がわかったと思います。
上手く使いこなすと非常に便利な機能ですのでぜひ活用していってください。
本当はオプション引数についても触れられればよかったのですが、またの機会ということで。