This is a stoics.infrastructure pack for handling option arguments. The main concept is to treat options as naive Prolog lists which the programmer can manipulate and specialise if they need to, while providing a small number of predicates that manage basic common operations on options. Options are particularly important in the context of SWI packs, as making code publicly available to others often involves allowing for variations in the behaviour of the code.
The library provides simple extensions to the basic list manipulation predicates. In many cases it is just the error handling that is the main difference to standard predicates.
Technically the library is designed on the semantics of memberchk/2. Looking for an Option in a list of options, memberchk/2 will return the leftmost match. Library(options) sees options as a concatenation (append/3) of the user provided options (arguments for hereon) and the defaults provided by the predicate.
The default option values for a predicate are given by a predicate of the same name but postfixed by '_defaults'. The library also allows for reading user specific default options by reading profiles from a file located at $HOME/.pl/<pred_name>.pl, if that file exists. Each options file should have a number of option terms given as facts.
Some distinctive features of pack(options)
debug(Dbg) terms which optionise calls to debug/1help(Help) and usage(Usg) uniformly; decluttering user's code (v
For an example see program options_example_sort_defaults.pl in examples directory.
?- edit( pack(options/examples/ex_sort) ). ?- [pack(options/examples/ex_sort)]. ?- ex_sort( [a,b,e,c,b], Ord, true ). Ord = [a, b, c, e]. ?- ex_sort( [a,b,e,c,b], Ord, debug(true) ). % Input list length: 5 % Output list length: 4 Ord = [a, b, c, e]. ?- ex_sort( [a,b,e,c,b], Ord, order(>) ). Ord = [e, c, b, a]. ?- ex_sort( [a,b,e,c,b], Ord, duplicates(true) ). Ord = [a, b, b, c, e].
Create file $HOME/.pl/ex_sort.pl with content
order(>).
?- ex_sort( [a,b,e,c,b], Ord, true ). Ord = [e, c, b, a].
Default for user is now order(>) which can still be over-ridden at invocation
?- ex_sort( [a,b,e,c,b], Ord, order(<) ). Ord = [a, b, c, e].
Predicates
Thanks to Jan Wielemaker for fixing an issue with expanding the $HOME variable and missing curly brackets in the errors DCG (2016/11/14).
Opts can also be non list as it is passed through en_list/2.
Options
The predicate fails silently if the first Required option with equivalent "shape" in Opts fails to pattern match (unlike classic memberchk/2).
?- options( x(y), [x(x)] ). false. ?- options( x(y), [x(x),x(y)] ). false. ?- options( x(X), [a(b),c(d),x(y),x(x)] ). X=y. ?- options( [a(X),c(b)], [a(b),x(x),b(c)] ). ERROR: Required option: c(b), not present in options: [a(b),x(x)] % Execution Aborted ?- options( x(X), [a(b),c(d),x(y),x(x)], rem_opts(Rem) ). X = y, Rem = [a(b), c(d)]. ?- options( x(X), [a(b),c(d),x(y),x(x)], en_list(true) ). X= [y]. ?- options( a(A), [a(X),b(c)], ground(error) ). ERROR: pack(options): Option should be ground, but found: a(_G1470), in options: [a(_G1470),b(c)] ?- options( a(A), [a(X),b(c)], ground(true) ). false. ?- options( a(A), [a(X),b(c)] ). A = X. ?- options( a(A), [a(X),b(c)], ground(false) ). A = X. ?- options( a(b), [a(a),a(b),b(c)], true(T) ). T = fail. ?- options( a(A), [a(a),a(b),b(c)], true(T) ). A = a, T = true. ?- options( a(a), [a(a),a(b),b(c)], true(T) ). T = true.
append_profile(false).debug(options_append).
The predicate processes the following options within Opts
debug(PredName) is called.
If Help or Usg are set to true $oa_cont(false)$ is returned else $oa_cont(true)$ is returned.
When _help ad _usage predicates are called debug channel PredName is turned on.
OptS and All are options of PredName, whereas OAopts are options of options_append/4 and control how OptS are transformed into All.
OAopts term or list of
options_types(OTypes),
this is removed and used to check the types of the supplied options.
OTypes should be OptName-Type pairs list with Type being one of those
recognised by type/2 in pack(pack_errors).debug_topic(PredName).
Else, debug(DbgMod(PredName) is enabled.
if false turn debugging off for this call.
if all, then if DbgMod is false debug(_) is enabled else debug(DbgMod(_)) is enabled.
Else Dbg can be a debug term (other than none,false,true) or list of debug terms.process() below,
but leaves processed options in All. (By default both debug and version are passed as funnel.)version(Vers) in Defs with the term <Pred>(PredVersion) where version(PredVersion) is
in OptSoptions_types(OTypes) to the result Options use Rtypes == falseWhen processing debugging options in All, the first matching term of the following is used:
debug(true)debug(Dbgs,_Prior)debug(PredName). For each element of Dbgs call RHS:debug(PredName)nodebug(PredName) same asdebug(_) same asdebug(Other) other?- assert( demo_defaults(ls(true)) ). ?- options_append( demo, ls(false), All ). All = [ls(false), ls(true)]. ?- options_append( demo, debug, All, process(debug) ). All = [ls(true)]. ?- options_append( demo, [debug(true),ls(false)], All, [process(debug),debug(true)] ). Turning debugging on for predicate handle: demo All = [ls(false), ls(true)]. % Note that the debug(options_append) has been removed in the following: ?- options_append( demo, debug, All, process(debug) ). All = [ls(true)]. ?- [pack(options/examples/ex_app)]. ?- ex_app. atoms([a,b,c]) opts([frg1(false),opt1(false),opt1(true)]) foreign([frg1(false)]) true. ?- lib(os_lib). ?- os_sel( os_files, ext(svg), Oses, version(V) ). Oses = [], V = [os_sel(0:1:3), os_file(0:0:4)|_9214].
The default OAopts list is [funnel(debug)].
debug(_,Format,Args) iff debug(true) is the first debug(_) term in
list Opts
?- options_debug( 'A simple message at: ~w', noon, [debug(true)] ). ?- options_debug( 'A simple message at: ~w', noon, [] ).
The predicate does not check arities.
The order in OptsOut follows the order in Onames.
PropOpts control the predicate behaviour
match(all) for no removalThis predicate is often called at the end of a deterministic call that depends on a set of options.
Currently the only option that is restored is
debug(Dbg)Internals; The predicate looks for any macthing '$restore'(Self,OptName,Status), so it should be extensible to other state-based options processing.
Opts is a listified OptS, and Terms of TermS.
The intension is that if Term is in Terms and memberchk(Term, Opts) succeeds, then any unbound parts of
Term will became ground of at least more ground than at call time.
If the memberchk/2 above fails, then by default the predicate succeeds. Values of the on_fail(OnFail)
option control that. Set to fail, for the predicate to fail and throw for an error to be raised.
The ball is thrown via throw/2 where ORoptS are passed as second argument, so the error can include
information about caller and pack it originated. See example below.
This predicate can be used to instantiate return options.
ORoptS
OptS, ORoptS and TermS are passed through options_en_list/2.
?- options_return( cnm(Cnm), [abc(x),cnm(symbols)] ). Cnm = symbols. ?- options_return( [data(Dt),cnm(Cnm)], [abc(x),cnm(symbols)] ). Cnm = symbols
?- ORopts = [on_fail(throw),pack(bio_analytics),pred(exp_reac_over/3)],
options_return( gid_to(to), [], ORopts ).
ERROR: bio_analytics:exp_reac_over/3 @ option(gid_to(to)): Only use return options for results- leave unbound at call time.
options(Opt,Opts)= succeeds.
Opts can in addition to Opt include
call_module(Mod=user)
which defines the calling module if one is not in Goal
?- options_call( write(true), (write(true),nl), write(true) ). true true. ?- options_call( write(flase), (write(true),nl), write(false) ). true. ?- options_call( write(true), user:(write(true),nl), write(true) ). true true.
Opts
call_module(Mod=user)
the module in which to call extended Goal
?- options_call( plus(2,X), plus(1) ). X = 3
options(debug(true),Opts), with Restore
being instantiated to a term that can be used to restore the
original debug state of Topic (see options_restore/2).
?- options_debug_topic( ex1, [debug(false)], Restore ). Restore = []. ?- options_debug_topic( ex1, [debug(true)], Restore ). Restore = ['$restore'(ex1, debug, false)].
RnmPairS is a single or list of pairs of the form OptNm-NewNm.
RnmOpts
Examples
?-
options_rename([a(1),b(2),c(3),b(4)], b-d, New, true).
New = [a(1), d(2), c(3), d(4)].
?-
options_rename([a(1),b(2),c(3)], b-c, New, true ).
New = [a(1), c(2)].
?-
options_rename([a(1),b(2),c(3)], b-c, New, replace(false) ).
New = [a(1), c(2), c(3)].
Currently:
?- options_version(Vers, Date). Date = date(2026,2,8), Vers = 1:6:0.