srfi.189
- MaybeとEither、オプショナルなコンテナ型 ¶MaybeとEitherは、任意個の値を「ラップ」する変更不可なコンテナ型です。 Maybeは値が「有効な値が無い」という状況で使えます (これは「ゼロ個の値を生成する」とは異なります)。 Eitherは「正常動作の時の値」と「エラー時の値」を区別したい状況で使えます。
Haskellのような関数型言語に親しんでいるなら、これらの型については既に ご存知でしょう。これらの型はモナドで使うととても便利です。 例えば、処理の連なりをまるで失敗が起きないかのように書きながら、 もし失敗が起きたら自動的に残りの処理がキャンセルされて失敗情報が帰ってくる、 というふうにできます。
Maybeは2つの型、JustとNothingのユニオン型です。 Justは有効な値(複数可)をラップし、Nothingは「有効な値がない」ことを示します。 Eitherは2つの型、RightとLeftのユニオン型です。 Rightは有効な値(複数可)をラップしLeftはエラー時の情報をラップします。
Schemeには多値があるので、他の言語と違ってJust、Right、Leftは
任意個の値を持てることに注意してください。
例えば2つの値を返す手続きf
をMaybeモナドの圏に持ち上げた手続きmf
は、
2つの値を持つJust
かNothing
を返すようになります。
ほとんどの場合は単一の値を扱うことになるでしょうが、
リファレンスを読む際には多値の場合の可能性を頭に置いておいてください。
• MaybeとEither - 型と述語: | ||
• MaybeとEither - コンストラクタ: | ||
• MaybeとEither - アクセサ: | ||
• MaybeとEither - シーケンス操作: | ||
• MaybeとEither - プロトコル変換: | ||
• Maybe and Either syntactic utilities: | ||
• Trivalent logic: |
{srfi.189
}
Maybe型のクラスです。<just>
と<nothing>
は<maybe>
のサブクラスです。
<just>
のインスタンスは任意個の値(ペイロード)を保持できます。
<nothing>
のインスタンスは値を保持しません。
<maybe>
クラス自体は抽象クラスで、それ自身のインスタンスは作りません。
<just>
と<nothing>
のインスタンスはそれぞれ
コンストラクタjust
およびnothing
で作ります。
{srfi.189
}
Either型のクラスです。<right>
と<left>
は<either>
のサブクラスです。
どちらのインスタンスは任意個の値(ペイロード)を保持できます。
慣習として、<right>
は正常な計算結果を運ぶのに使われ、
<left>
は異常が生じた時に何が異常かの情報を運ぶのに使われます。
<either>
クラス自体は抽象クラスで、それ自身のインスタンスは作りません。
<right>
と<left>
のインスタンスはそれぞれ
コンストラクタright
およびleft
で作ります。
[SRFI-189]{srfi.189
}
型検査述語です。
それぞれ、objがMaybe, Just, Nothingである場合に#t
を、
そうでなければ#f
を返します。
[SRFI-189]{srfi.189
}
型検査述語です。
それぞれ、objがEither, Right, Leftである場合に#t
を、
そうでなければ#f
を返します。
[SRFI-189]{srfi.189
}
Maybeについての等価判定述語です。NothingはNothingのみと等価であり、
Justはその対応するペイロード同士が全てelt=
で比較して等価な場合にのみ
等価です。
[SRFI-189]{srfi.189
}
Eitherについての等価判定述語です。
Rightは同じペイロードを持つRightのみと、
Leftは同じペイロードを持つLeftのみと等価です。
ペイロード同士はelt=
で比較されます。
[SRFI-189]{srfi.189
}
obj …をペイロードに持つJustのインスタンスを返します。
[SRFI-189]{srfi.189
}
Nothingのインスタンスを返します。
[SRFI-189]{srfi.189
}
obj …をペイロードに持つ、それぞれRightとLeftのインスタンスを返します。
[SRFI-189]{srfi.189
}
リストで与えられるオブジェクトをペイロードに持つ、Just、Right、Left
のインスタンスをそれぞれ返します。
[SRFI-189]{srfi.189
}
maybe引数はMaybeでなければなりません。
引数がJustの場合は。同じペイロードを持つRightが、
Nothingの場合は、obj …をペイロードに持つLeftが返されます。
[SRFI-189]{srfi.189
}
either引数はEitherでなければなりません。
引数がRightの場合は。同じペイロードを持つJustが、
Leftの場合はNothingが返されます。
[SRFI-189]{srfi.189
}
either引数はEitherでなければなりません。
引数がRightの場合は。同じペイロードを持つLeftが、
Leftの場合は同じペイロードを持つRightが返されます。、
[SRFI-189]{srfi.189
}
maybe引数はMaybeでなければなりません。
それがNothingなら、手続きfailureが引数なしで末尾呼び出しされます。
Justの場合は手続きsuccessが、Justのペイロードを引数として末尾呼び出しされます。
successが省略された場合はvalues
が使われます。
(maybe-ref (just 1 2) (^[] (error 'huh?)) +) ⇒ 3
[SRFI-189]{srfi.189
}
either引数はEitherでなければなりません。
それがLeftなら、手続きfailureが、
Rightの場合は手続きsuccessがペイロードを引数として末尾呼び出しされます。
successが省略された場合はvalues
が使われます。
[SRFI-189]{srfi.189
}
maybe引数はMaybeでなければなりません。
それがNothingなら、default …が値として返されます。
Justの場合はそのペイロードが値として返されます。
(maybe-ref/default maybe obj ...) ≡ (maybe-ref maybe (^[] (values obj ...)))
[SRFI-189]{srfi.189
}
either引数はEitherでなければなりません。
それがLeftなら、そのペイロードは捨てられ、
default …が値として返されます。
Rightの場合はそのペイロードが値として返されます。
(either-ref/default either obj ...) ≡ (either-ref either (^ _ (values obj ...)))
[SRFI-189]{srfi.189
}
maybeがNothingならそのまま返されます。
それがJustで、一つだけの値を持ち、その値がMaybeならそれが返されます。
それ以外の場合はエラーが投げられます。
[SRFI-189]{srfi.189
}
eitherがLeftならそのまま返されます。
それがRightで、一つだけの値を持ち、その値がEitherならそれが返されます。
それ以外の場合はエラーが投げられます。
[SRFI-189]{srfi.189
}
モナドのbindです。maybeはMaybeでなければならず、
mproc mproc2 …のそれぞれはMaybeを返す手続きでなければなりません。
maybeがNothingならそれがそのまま返されます。 Justの場合は、そのペイロードを引数としてmprocが呼ばれます。 mproc2 …があれば同様に操作が繰り返されます。
(maybe-bind m p p2) ≡ (maybe-bind (maybe-bind m p) p2)
[SRFI-189]{srfi.189
}
モナドのbindです。eitherはEithereでなければならず、
mproc mproc2 …のそれぞれはEitherを返す手続きでなければなりません。
eitherがLeftならそれがそのまま返されます。 Rightの場合は、そのペイロードを引数としてmprocが呼ばれます。 mproc2 …があれば同様に操作が繰り返されます。
(either-bind e p p2) ≡ (either-bind (either-bind e p) p2)
[SRFI-189]{srfi.189
}
mproc mproc2 … はそれぞれ、ゼロ個以上の引数を取り
Maybe/Eitherを返す手続きでなければなりません。
返り値は、ゼロ個以上の引数を取りMaybe/Eitherを返す手続きになります。
作られた手続きが呼ばれると、まずmprocが呼ばれます。それがNothing/Left を返した場合、あるいはもうmprocが無い場合はそれがそのまま返されます。 Just/Rightの場合は、そのペイロードを引数として次のmprocが呼ばれ、 それが繰り返されます。
(maybe-bind m p p2 ...) ⇒ (maybe-ref m (^[] (nothing)) (maybe-compose p p2 ...))
MaybeとEitherは、0個または1個の要素を持つシーケンスとみなせます。 この視点からMaybe/Eitherを扱う手続きがいくつかあります (註: この用途においては、複数のペイロードはひとまとめにして1要素と して扱われます。手続き呼び出しや手続きからのリターンが、いくつ引数や返り値が あってもワンステップと考えられるのと同様です)。
[SRFI-189]{srfi.189
}
maybe/eitherがNothing/Leftなら0を、
Just/Rightなら1を返します。
引数がMaybe/Eitherでなければエラーが投げられます。
[SRFI-189]{srfi.189
}
maybe/eitherがNothing/Leftなら、
それぞれNothingもしくはobj …をペイロードに持つLeftを返します。
maybe/eitherがJust/Rightなら、そのペイロードを引数として
predを呼び、それが真の値を返したら
maybe/eitherがそのまま返されます。
そうでなければNothingもしくはobj …をペイロードに持つLeftが返されます。
[SRFI-189]{srfi.189
}
predの意味が逆になることを除いて、
maybe-filter
/either-filter
と同じです。
[SRFI-189]{srfi.189
}
この手続きは、Maybe/Eitherのコレクションを、
コレクションのMaybe/Eitherへと変換します。
入力となるコレクションと出力となるコレクションの型は違っていても構いません。
これは、Haskell的なタイプシグネチャを使った方が(厳密ではありませんが)
わかりやすいでしょう。
Container x
を何らかの型xのオブジェクトのコレクション、
a*
を任意の型の多値とします。
Mappable = Container Maybe a* CMap = ((Maybe a* -> b) -> Container Maybe a* -> Container' b Aggregator = a* -> b maybe-sequence :: Mappable -> CMap -> Aggregator -> Container' b
入力コンテナの要素が全てJustであれば、
cmapは最初の引数である手続き入力のコンテナmappableの各要素に適用し、
結果を別のコンテナに集積します。mappableと型があってさえいれば、
各コンテナの型は任意です。
例えばmappableにMaybeのベクタ、cmapにvector-map
を
渡すことができます。この場合、Container
とContainer'
の型は
どちらもベクタです。あるいは、mappableはMaybeのリストで、
cmapに(cut map-to <string> <> <>)
を渡すこともできます。
この場合、Container
はリスト、Container'
は文字列となります。
a*
とb
の型はaggregator手続きにより決定されます。
デフォルトの値はlist
です。
(use gauche.sequence) ; generic map (map-sequence (vector (just 'a 'b) (just 'c 'd 'e) (just 'f)) map vector) ⇒ #<Just (#(a b) #(c d e) #(f))>
入力コンテナの中にNothingがあればそれがそのまま返されます。
either-sequence
の動作も、Just/NothingをRight/Leftに入れ替える
だけで同様です。入力シーケンスにLeftが含まれていた場合は
最初のLeftがそのまま返されます。
[SRFI-189]{srfi.189
}
maybe/eitherがNothing/Leftならばそれがそのまま返されます。
Just/Rightである場合は、そのペイロードがprocに渡され、結果が
Just/Rightにくるんで返されます。
(maybe-map quotient&remainder (just 18 4)) ⇒ #<Just 4 2>
[SRFI-189]{srfi.189
}
maybe/eitherがNothing/Leftならば何もしません。
Just/Rightならば、そのペイロードを引数としてprocが呼ばれます。
procの結果は捨てられます。
[SRFI-189]{srfi.189
}
maybe/eitherがNothing/Leftならknilが返されます。
Just/Rightならそのペイロードおよびknilを引数としてkonsが呼ばれ、
その結果が返されます。
(maybe-fold vector 'z (just 'a 'b)) ⇒ #(a b z)
[SRFI-189]{srfi.189
}
まず、終了述語pがseed …を引数として呼ばれます。
それが真の値を返したら、Nothingおよびseed …をペイロードとする
Leftがそれぞれ返されます。
そうでなければ次のシードを生成するgがseed …を引数として
呼ばれます。gは引数と同じ数の値を返さねばなりません。
gの戻り値はpに渡され終了条件がチェックされます。
もしpが真の値を返さなかったらエラーが投げられます
(シーケンスとしてのMaybe/Eitherはたかだか1個の要素しか持てないので)。
そうでなければ、seed …が値生成手続きfに渡され、
その結果がJust/Rightにラップされて返されます。
[SRFI-189]{srfi.189
}
maybeがJustならば、そのペイロードのリストが返されます。
Nothingならば空リストが返されます。
(戻り値が空リストになるのは、maybeがNothingである場合と
ゼロ個のペイロードを持つJustである場合があります)
これは「シーケンスとしてのMaybe」をリストに変換するものではないことに
注意してください。シーケンスとして見た場合、Justはつねに一つだけの
要素を持ちます。ただ、その要素が多値である場合があります。
この手続きは概念的にはvalues->list
に似ています。
[SRFI-189]{srfi.189
}
lisが空リストならNothingが、そうでなければ
lisの各要素をペイロードとして持つJustが返されます。
(list->maybe (maybe->list x))
は恒等関数ではないことに
注意して下さい。xがゼロ個のペイロードを持つJustの場合、
この式はNothingを返します。
[SRFI-189]{srfi.189
}
maybeがRightならば、そのペイロードのリストが返されます。
Leftならば空リストが返されます。
(戻り値が空リストになるのは、eitherがLeftである場合と
ゼロ個のペイロードを持つRightである場合があります)
[SRFI-189]{srfi.189
}
lisが空リストならobj …をペイロードとして持つLeftが、
そうでなければlisの各要素をペイロードとして持つRightが返されます。
[SRFI-189]{srfi.189
}
maybeがNothingなら#f
が、ペイロードとして値をひとつだけ持つJustなら
その値が返されます。ペイロードに1つ以外の値を持つJustだった場合は
エラーが投げられます。任意のペイロードを扱いたい場合は
下のmaybe->list-truth
を使って下さい。
#f
が帰って来た場合に、元がNothingだったのか#f
を値として
持つJustだったのか区別できないことに注意してください。
この手続きは、Maybeインタフェースと、従来の「Maybe的な」インタフェースとの
橋渡しをします。例えばfind
は述語を満たす要素が無かった場合に
#f
を返しますが、「述語を満たす要素」が#f
である場合を扱えません。
その意味で「Maybe的な」インタフェースは不完全なんですが、それを期待している
従来のコードにMaybeを使った結果を返したい場合にこの手続きが使えます。
[SRFI-189]{srfi.189
}
objが#f
ならNothingを、そうでなければ
objをペイロードに持つJustを返します。
(truth->maybe (maybe->truth x))
は恒等関数ではないことに注意して下さい。
xが(just #f)
だった場合、この式の値はNothingになります。
[SRFI-189]{srfi.189
}
eitherがLeftなら#f
が、
ひとつの値を持つRightならその値が返されます。
eitherが一つ以外の値を持つRightであった場合はエラーが投げられます。
任意個のペイロードを持つRightを扱いたい場合は
either->list-truth
が使えます。
[SRFI-189]{srfi.189
}
objが#f
ならfail-obj …をペイロードに持つLeftが、
そうでなければobjをペイロードに持つRightが返されます。
[SRFI-189]{srfi.189
}
maybe->list
と同じように、maybeがNothingの場合は#f
を
返しますが、Justの場合はペイロードのリストを返します。
[SRFI-189]{srfi.189
}
引数はリストか#f
でなければなりません。
引数が#f
ならばNothingが返されます。
引数がリストの場合は、それらの各要素をペイロードとするJustが返されます。
(list-truth->maybe (maybe->list-truth x))
はxの恒等写像です。
[SRFI-189]{srfi.189
}
either->list
と同じように、eitherがRightならば
そのペイロードの値のリストが返されます。
しかしeitherがLeftの場合は#f
が返されます。
[SRFI-189]{srfi.189
}
list-or-false引数はリストか#f
でなければなりません。
#f
の場合は、fail-objs …をペイロードとするLeftが、
リストの場合はその各要素をペイロードとするRightが返されます。
[SRFI-189]{srfi.189
}
maybeがNothingならEOFを、
ペイロードをひとつ持つJustならその値を返します。
それ以外の場合はエラーが投げられます。
[SRFI-189]{srfi.189
}
objがEOFならNothingが、
そうでなければobjをペイロードとするJustが返されます。
[SRFI-189]{srfi.189
}
eitherがLeftならEOFを、
ペイロードをひとつ持つRightならその値を返します。
それ以外の場合はエラーが投げられます。
[SRFI-189]{srfi.189
}
objがEOならfail-objs …をペイロードに持つLeftが、
そうでなければobjをペイロードに持つRightが返されます。
[SRFI-189]{srfi.189
}
maybeがJustなら、そのペイロードを多値で返します。
Nothingならゼロ個の値を返します。
(ゼロ個のペイロードを持つJustだった場合もゼロ個の値が返されることに注意してください)。
[SRFI-189]{srfi.189
}
まず手続きproducerを引数なしで呼び出します。
それがゼロ個の値を返した場合はNothingが、そうでなければ
値をペイドーロとするJustが返されます。
[SRFI-189]{srfi.189
}
eitherがRightなら、そのペイロードを多値で返します。
Leftならゼロ個の値を返します。
(ゼロ個のペイロードを持つRightだった場合もゼロ個の値が返されることに注意してください)。
[SRFI-189]{srfi.189
}
まず手続きproducerを引数なしで呼び出します。
それがゼロ個の値を返した場合は、fail-obj …をペイロードとする
Leftが、そうでなければ値をペイドーロとするRightが返されます。
[SRFI-189]{srfi.189
}
maybeがひとつのペイロードを持つJustであれば、その値と#t
を
2つの値として返します。
maybeがNothingならば、2つの#f
を返します。
maybeがそれ以外の場合はエラーが投げられます。
2つ目の値によって、呼び出し側は引数がNothingだったのか
#f
をペイロードに持つJustだったのかを区別できます。
[SRFI-189]{srfi.189
}
maybe->two-values
の逆です。
手続きproducerが引数無しで呼ばれます。それは2つの値を返さねばなりません。
2つ目の値が真ならば、1つ目の値をペイロードとするJustが、
そうでなければNothingが返されます(1つ目の値は捨てられます)。
[SRFI-189]{srfi.189
}
例外ハンドラを設定したうえで、手続きthunkが引数なしで呼ばれます。
thunkが例外を投げた場合、そのコンディションオブジェクトがpredに
渡されます。predが真を返した場合は、コンディションがLeftにラップされて
返されます。predが#f
を返した場合は同じ例外が再び投げられます。
例外が投げられなかった場合は、thunkの戻り値がRightにラップされて
返されます。
[SRFI-189]{srfi.189
}
If the mtest expression yields a Just, evaluates then.
If the mtest expression yeilds a Nothing, evaluates else.
If the mtest expression doesn’t produce a Maybe, an error
is thrown.
[SRFI-189]{srfi.189
}
Evaluates maybe/either from left to right, as far as
each yields a Just/Right. If every expression yields a Just/Right,
the last one is returned. If it encounters an expression that
yields a Nothing/Left, it stops evaluating the rest of expressions and
returns the Nothing/Left.
If expressions yield something other than Maybe/Either, an error is thrown.
[SRFI-189]{srfi.189
}
Evaluates maybe/either from left to right, as far as
each yields a Nothing/Left. If it encounters an expression that
yields a Just/Right, it stops evaluating the rest of expressions and
returns it.
If expressions yield something other than Maybe/Either, an error is thrown.
[SRFI-189]{srfi.189
}
This is a Maybe/Either version of and-let*
.
Each claw can be either one of the following forms:
identifier
The identifier’s value is taken. It must be a Maybe/an Either, or an error is signaled. If it is a Just/Right, evaluation proceeds to the next claw. If it is a Nothing/Left, evaluation stops and the value is returned immediately.
(identifier expression)
The expression is evaluated. It must yield a Maybe/an Either, or an error is signaled. If it is a Just/Right, identifier is bound to its payload, and the rest of claws and body are processed with the scope of identifier. If it is a Nothing/Left, evaluation stops and the value is returned immediately. An error is signaled if a Just/Right doesn’t carry exactly one value.
( expression )
The expression is evaluated. It must yield a Maybe/an Either, or an error is signaled. If it is a Just/Right, evaluation proceeds to the next claw. If it is a Nothing/Left, evaluation stops and the value is returned immediately.
After all claws are processed and none yields a Nothing/Left, body … are evaluated.
[SRFI-189]{srfi.189
}
Multi-value payload version of maybe-let*
/either-let*
.
Each claw can be either one of the following forms:
identifier
The identifier’s value is taken. It must be a Maybe/an Either, or an error is signaled. If it is a Just/Right, evaluation proceeds to the next claw. If it is a Nothing/Left, evaluation stops and the value is returned immediately.
(formals expression)
The formals is the same as the formals of the lambda form, that is, a proper or dotted list of identifiers.
The expression is evaluated. It must yield a Maybe/an Either, or an error is signaled. If it is a Just/Right, identifiers in the formals are bound with the payload of the Just/Right, and the rest of claws and body are processed with the scope of those identifiers. If it is a Nothing/Left, evaluation stops and the value is returned immediately. An error is signaled if the formals doesn’t match the payload of the Just/Right.
( expression )
The expression is evaluated. It must yield a Maybe/an Either, or an error is signaled. If it is a Just/Right, evaluation proceeds to the next claw. If it is a Nothing/Left, evaluation stops and the value is returned immediately.
After all claws are processed and none yields a Nothing/Left, body … are evaluated.
[SRFI-189]{srfi.189
}
The body … is evaluated, and the value(s) it produces
are wrapped in a Right and returned. If an exception occurs in
body …, the thrown condition is passed to a predicate pred.
If the condition satisfies the predicate, it is wrapped in a Left
and returned. Otherwise, the condition is reraised with
raise-continuable.
This section describes procedures that deal with trivalent logic—a value can
be a false value (Just #f
), a true value
(Just
with anything other than #f
), and Nothing
.
If any of the arguments is Nothing
, the result becomes Nothing
(except tri=?
).
All the argument must be Maybe type, or an error is signalled.
[SRFI-189]{srfi.189
}
Returns Just #t
if maybe is trivalent-false,
Just #f
if maybe is triavlent-true, and
Nothing
if maybe is Nothing
.
[SRFI-189]{srfi.189
}
Returns Just #t
if arguments are either all trivalent-true
or all trivalent-false. Otherwise return Just #f
.
Note that if any of the argument is Nothing
, the result is
Just #f
(even all arguments are Nothing
).
[SRFI-189]{srfi.189
}
Returns Just #t
if all arguments are trivalent-true,
Just #f
if all arguments are Just
but at least one
of them is Just #f
, and Nothing
if any of the arguments
is Nothing
. If there’s no arguments, Just #t
is returned.
This is not a shortcut operation like and
.
[SRFI-189]{srfi.189
}
Returns Just #f
if all arguments are trivalent-false,
Just #t
if all arguments are Just
but at least one
of them is trivalent-true, and Nothing
if any of the arguments
is Nothing
. If there’s no arguments, Just #f
is returned.
This is not a shortcut operation like or
.
[SRFI-189]{srfi.189
}
If all arguments are Nothing
, Nothing
is returned.
Otherwise, first Just
is returned.