update to more recent version of option.pl

This commit is contained in:
Vitor Santos Costa 2010-07-28 10:45:06 +01:00
parent 86af6ff3f6
commit ca94b17049
1 changed files with 149 additions and 11 deletions

View File

@ -1,11 +1,11 @@
/* $Id: option.pl,v 1.1 2008-02-12 17:03:53 vsc Exp $
/* $Id$
Part of SWI-Prolog
Author: Jan Wielemaker
E-mail: jan@swi.psy.uva.nl
E-mail: J.Wielemaker@uva.nl
WWW: http://www.swi-prolog.org
Copyright (C): 1985-2002, University of Amsterdam
Copyright (C): 1985-2009, University of Amsterdam
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@ -33,21 +33,62 @@
[ option/2, % +Term, +List
option/3, % +Term, +List, +Default
select_option/3, % +Term, +Options, -RestOpts
select_option/4 % +Term, +Options, -RestOpts, +Default
select_option/4, % +Term, +Options, -RestOpts, +Default
merge_options/3, % +New, +Old, -Merged
meta_options/3 % :IsMeta, :OptionsIn, -OptionsOut
]).
:- use_module(library(lists)).
/** <module> Option list processing
The library(option) provides some utilities for processing option lists.
Option lists are commonly used as an alternative for many arguments.
Examples built-in predicates are open/4 and write_term/3. Naming the
arguments results in more readable code and the list nature makes it
easy to extend the list of options accepted by a predicate. Option lists
come in two styles, both of which are handled by this library.
$ Name(Value) :
This is the preferred style.
$ Name = Value :
This is often used, but deprecated.
Processing options inside time critical code (loops) can cause serious
overhead. One possibility is to define a record using library(record)
and initialise this using make_<record>/2. In addition to providing good
performance, this also provides type-checking and central declaration of
defaults.
==
:- record atts(width:integer=100, shape:oneof([box,circle])=box).
process(Data, Options) :-
make_atts(Options, Attributes),
action(Data, Attributes).
action(Data, Attributes) :-
atts_shape(Attributes, Shape),
...
==
@tbd We should consider putting many options in an assoc or record
with appropriate preprocessing to achieve better performance.
@tbd We should provide some standard to to automatic type-checking
on option lists.
@see library(record)
*/
%% option(?Option, +OptionList, +Default)
%
% Get an option from a OptionList. OptionList can use the
% Name=Value as well as the Name(Value) convention.
%
%
% @param Option Term of the form Name(?Value).
option(Opt, Options, Default) :- % make option processing stead-fast
arg(1, Opt, OptVal),
nonvar(OptVal), !,
ground(OptVal), !,
functor(Opt, OptName, 1),
functor(Gen, OptName, 1),
option(Gen, Options, Default),
@ -62,7 +103,7 @@ option(Opt, _, Default) :-
% Get an option from a OptionList. OptionList can use the
% Name=Value as well as the Name(Value) convention. Fails silently
% if the option does not appear in OptionList.
%
%
% @param Option Term of the form Name(?Value).
option(Opt, Options) :- % make option processing stead-fast
@ -86,8 +127,9 @@ get_option(Opt, Options) :-
%% select_option(?Option, +Options, -RestOptions) is semidet.
%
% As option/2, removing the matching option from Options and
% unifying the remaining options with RestOptions.
% Get and remove option from an option list. As option/2, removing
% the matching option from Options and unifying the remaining
% options with RestOptions.
select_option(Opt, Options0, Options) :- % stead-fast
arg(1, Opt, OptVal),
@ -109,10 +151,106 @@ get_option(Opt, Options0, Options) :-
%% select_option(?Option, +Options, -RestOptions, +Default) is det.
%
% As select_option/3, but if Option is not in Options, its value
% is unified with Default and RestOptions with Options.
% Get and remove option with default value. As select_option/3,
% but if Option is not in Options, its value is unified with
% Default and RestOptions with Options.
select_option(Option, Options, RestOptions, _Default) :-
select_option(Option, Options, RestOptions), !.
select_option(Option, Options, Options, Default) :-
arg(1, Option, Default).
%% merge_options(+New, +Old, -Merged) is det.
%
% Merge two option lists. Merged is a sorted list of options using
% the canonical format Name(Value) holding all options from New
% and Old, after removing conflicting options from Old.
merge_options([], Old, Merged) :- !, Merged = Old.
merge_options(New, [], Merged) :- !, Merged = New.
merge_options(New, Old, Merged) :-
canonise_options(New, NCanonical),
canonise_options(Old, OCanonical),
sort(NCanonical, NSorted),
sort(OCanonical, OSorted),
ord_merge(NSorted, OSorted, Merged).
ord_merge([], L, L) :- !.
ord_merge(L, [], L) :- !.
ord_merge([NO|TN], [OO|TO], Merged) :-
functor(NO, NName, 1),
functor(OO, OName, 1),
compare(Diff, NName, OName),
ord_merge(Diff, NO, NName, OO, OName, TN, TO, Merged).
ord_merge(=, NO, _, _, _, TN, TO, [NO|T]) :-
ord_merge(TN, TO, T).
ord_merge(<, NO, _, OO, OName, TN, TO, [NO|T]) :-
( TN = [H|TN2]
-> functor(H, NName, 1),
compare(Diff, NName, OName),
ord_merge(Diff, H, NName, OO, OName, TN2, TO, T)
; T = [OO|TO]
).
ord_merge(>, NO, NName, OO, _, TN, TO, [OO|T]) :-
( TO = [H|TO2]
-> functor(H, OName, 1),
compare(Diff, NName, OName),
ord_merge(Diff, NO, NName, H, OName, TN, TO2, T)
; T = [NO|TN]
).
%% canonise_options(+OptionsIn, -OptionsOut) is det.
%
% Rewrite option list from possible Name=Value to Name(Value)
canonise_options(In, Out) :-
memberchk(_=_, In), !, % speedup a bit if already ok.
canonise_options2(In, Out).
canonise_options(Options, Options).
canonise_options2([], []).
canonise_options2([Name=Value|T0], [H|T]) :- !,
H =.. [Name,Value],
canonise_options2(T0, T).
canonise_options2([H|T0], [H|T]) :- !,
canonise_options2(T0, T).
%% meta_options(+IsMeta, :Options0, -Options) is det.
%
% Perform meta-expansion on options that are module-sensitive.
% Whether an option name is module sensitive is determined by
% calling call(IsMeta, Name). Here is an example:
%
% ==
% meta_options(is_meta, OptionsIn, Options),
% ...
%
% is_meta(callback).
% ==
:- meta_predicate
meta_options(1, :, -).
meta_options(IsMeta, Context:Options0, Options) :-
meta_options(Options0, IsMeta, Context, Options).
meta_options([], _, _, []).
meta_options([H0|T0], IM, Context, [H|T]) :-
meta_option(H0, IM, Context, H),
meta_options(T0, IM, Context, T).
meta_option(Name=V0, IM, Context, Name=M:V) :-
call(IM, Name), !,
strip_module(Context:V0, M, V).
meta_option(O0, IM, Context, O) :-
compound(O0),
O0 =.. [Name,V0],
call(IM, Name), !,
strip_module(Context:V0, M, V),
O =.. [Name,M:V].
meta_option(O, _, _, O).