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
}
If obj is #f
, returns a Nothing.
Otherwise, returns a Just with obj as its payload.
Note that (truth->maybe (maybe->truth x))
isn’t an identity mapping—
if x is a Just wrapping #f
, you’ll get a Nothing.
[SRFI-189]{srfi.189
}
If either is a Left, #f
is returned.
Otherwise, it must be a Right with one value, and its value is returned.
If either is a Right and it doesn’t have exactly one value, an error
is thrown. If you want to deal with arbitrary number of payload values,
use either->list-truth
.
[SRFI-189]{srfi.189
}
If obj is #f
, returns a Left with fail-obj … is
returned.
Otherwise, returns a Right with obj as its payload.
[SRFI-189]{srfi.189
}
Like maybe->list
, it returns #f
if maybe is a Nothing.
If maybe is a Just, however, it returns a list of its payload values.
[SRFI-189]{srfi.189
}
The argument must be #f
of a list. If it is #f
, a Nothing
is returned. If it is a list, a Just with elements of the list is
returned.
(list-truth->maybe (maybe->list-truth x))
is an identity mapping.
[SRFI-189]{srfi.189
}
Like either->list
, it returns #f
if either is a Left.
If either is a Right, however, it returns a list of its payload values.
[SRFI-189]{srfi.189
}
The list-or-false argument must be #f
of a list.
If it is #f
, a Left with fail-objs …
is returned. If it is a list, a Right with elements of the list is
returned.
[SRFI-189]{srfi.189
}
If maybe is a Nothing, an EOF object is returned.
Otherwise, it must be a Just with one value, and its value is returned.
If maybe is a Just and it doesn’t have exactly one value, an error
is thrown.
[SRFI-189]{srfi.189
}
If obj is an EOF value, a Nothing is returned.
Otherwise, a Just wrapping obj is returned.
[SRFI-189]{srfi.189
}
If either is a Left, an EOF object is returned.
Otherwise, it must be a Right with one value, and its value is returned.
If either is a Right and it doesn’t have exactly one value, an error
is thrown.
[SRFI-189]{srfi.189
}
If obj is an EOF value, a Left with fail-objs … is returned.
Otherwise, a Right wrapping obj is returned.
[SRFI-189]{srfi.189
}
If maybe is a Just, returns its payload as multiple values.
If it is a Nothing, returns no values.
(Note that a Just with zero values also returns no values.)
[SRFI-189]{srfi.189
}
It first invokes a procedure producer with no values.
If it returns zero values, a Nothing is returned; otherwise,
a Just with those values are returned.
[SRFI-189]{srfi.189
}
If either is a Right, returns its payload as multiple values.
If it is a Left, returns no values.
(Note that a Right with zero values also returns no values.)
[SRFI-189]{srfi.189
}
It first invokes a procedure producer with no values.
If it returns zero values, a Left with fail-obj … as
its payload is returned.
If it returns one or more values,
a Right with those values are returned.
[SRFI-189]{srfi.189
}
If maybe is a Just with exactly one value, the value and #t
is returned. If maybe is a Nothing, two #f
is returned.
An error is thrown if maybe has a Just with zero or more than two
values.
[SRFI-189]{srfi.189
}
The inverse of maybe->two-values
. A procedure producer
is called with no arguments. It must return two values, a possible
payload value, and a boolean. If the second value is true,
a Just with the first value is returned. If the second value is #f
,
a Nothing is returned (the first return value is ignored).
[SRFI-189]{srfi.189
}
A procedure thunk is called without argument, wrapped by an
exception handler. If thunk raises a condition, it is
examined by pred. If pred returns true on the condition,
the exception is wrapped by a Left and returned.
If pred returns #f
, the exception is reraised.
If no exception is raised, the result(s) of thunk is wrapped
by a Right and returned.
[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.