1:- module(maybe, [ call_maybe/3 2 , is_just/1 3 , is_nothing/1 4 , just_value/2 5 , maybe_value/2 6 , maybe_list/2 7 , maybe_default_value/3 8 , default_maybe_value/3 9 , map_maybe/3 10 , fold_maybe/4 11 ]). 12:- use_module(library(error), [ domain_error/2 ]). 13 14 15:- multifile error:has_type/2. 16errorhas_type(maybe, Maybe) :- 17 nonvar(Maybe), 18 memberchk(Maybe, [nothing, just(_)]). 19errorhas_type(maybe(T), Maybe) :- 20 error:has_type(maybe, Maybe), 21 ( Maybe = just(X) -> 22 error:has_type(T, X) 23 ; true 24 ). 25 26% we don't load library(quickcheck) to avoid a dependency 27:- multifile quickcheck:arbitrary/2. 28quickcheckarbitrary(maybe, Maybe) :- 29 quickcheck:arbitrary(maybe(any), Maybe). 30quickcheckarbitrary(maybe(T), Maybe) :- 31 random_between(0, 4, N), 32 ( N == 0 -> 33 Maybe = nothing 34 ; % otherwise -> 35 quickcheck:arbitrary(T, X), 36 Maybe = just(X) 37 ). 38 39:- multifile quickcheck:shrink/3. 40quickcheckshrink(maybe(T), just(X0), just(X)) :- 41 quickcheck:shrink(T, X0, X).
just(_)
. Useful for include/3.
47is_just(just(_)).
nothing
. Useful for exclude/3.
53is_nothing(nothing).
nothing
.61just_value(just(Value), Value) :- 62 !. 63just_value(nothing, _) :- 64 domain_error(just, nothing).
just(Value)
; fails for nothing
.
70maybe_value(just(Value), Value).
call(Goal)
succeeds, Maybe=just(Value)
, otherwise
Maybe=nothing
. Goal typically binds Value. If Goal produces
multiple solutions on backtracking, so will call_maybe/3. In that
case, Maybe will never be nothing
.
For example,
?- L = [a,b,c], call_maybe(L=[H|_], H, MaybeHead). H = a, MaybeHead = just(a). ?- L = [], call_maybe(L=[H|_], H, MaybeHead). MaybeHead = nothing.
Of course, that particular example could have been implemented with maybe_list/2 instead.
90:- meta_predicate call_maybe( , , ). 91call_maybe(Goal, Value, Maybe) :- 92 ( call(Goal) *-> 93 just_value(Maybe, Value) 94 ; % no solutions -> 95 Maybe = nothing 96 ).
nothing
. A non-empty list is equivalent to just(Head)
.103maybe_list(nothing, []). 104maybe_list(just(H), [H|_]).
nothing
case.111maybe_default_value(nothing, Default, Default). 112maybe_default_value(just(Value), _, Value).
maplist(default_maybe_value(7), Maybes, DefaultedValues).
121default_maybe_value(Default, Maybe, Value) :-
122 maybe_default_value(Maybe, Default, Value).
call(Goal, Value0, Value)
succeeds for just
values. Goal
is not called for nothing
values, which remain unchanged. "Use the
source" for a clearer explanation.130:- meta_predicate map_maybe( , , ). 131map_maybe(_, nothing, nothing) :- 132 !. % help indexer 133map_maybe(Goal, just(V0), just(V)) :- 134 call(Goal, V0, V).
nothing
leaves Accum0=Accum
while just
relates them via Goal.
"Use the source" for a clearer explanation.141:- meta_predicate fold_maybe( , , , ). 142fold_maybe(_, nothing, Accum, Accum). 143fold_maybe(Goal, just(Value), Accum0, Accum) :- 144 call(Goal, Value, Accum0, Accum)