Migrate from Markdown to Djot

This commit is contained in:
Adrián Arroyo Calle
2023-01-19 21:15:25 +01:00
parent 84583da5b8
commit 46d1e3bee3
11 changed files with 334 additions and 243 deletions

View File

@@ -172,7 +172,7 @@ gen_assoc_(Key, t(_,_,_,_,R), Val) :-
% %
% True if Key-Value is an association in Assoc. % True if Key-Value is an association in Assoc.
% %
% Throws error: type_error(assoc, Assoc) if Assoc is not an association list. % Throws error: type\_error(assoc, Assoc) if Assoc is not an association list.
get_assoc(Key, Assoc, Val) :- get_assoc(Key, Assoc, Val) :-
must_be(assoc, Assoc), must_be(assoc, Assoc),
@@ -218,7 +218,7 @@ get_assoc(>, Key, V, L, R, Val, V, L, NR, NVal) :-
% Create an association from a list Pairs of Key-Value pairs. List % Create an association from a list Pairs of Key-Value pairs. List
% must not contain duplicate keys. % must not contain duplicate keys.
% %
% Throws error: domain_error(unique_key_pairs, List) if List contains duplicate keys % Throws error: domain\_error(unique\_key\_pairs, List) if List contains duplicate keys
list_to_assoc(List, Assoc) :- list_to_assoc(List, Assoc) :-
( List = [] -> Assoc = t ( List = [] -> Assoc = t
@@ -249,7 +249,7 @@ list_to_assoc(N, List, More, Depth, t(K,V,Balance,L,R)) :-
% pairs. The pairs must occur in strictly ascending order of % pairs. The pairs must occur in strictly ascending order of
% their keys. % their keys.
% %
% Throws error: domain_error(key_ordered_pairs, List) if pairs are not ordered. % Throws error: domain\_error(key\_ordered\_pairs, List) if pairs are not ordered.
ord_list_to_assoc(Sorted, Assoc) :- ord_list_to_assoc(Sorted, Assoc) :-
( Sorted = [] -> Assoc = t ( Sorted = [] -> Assoc = t

View File

@@ -105,53 +105,60 @@ goal_expansion(del_attr(Var, Module), (var(Var) -> put_atts(Var, -Access);true))
Access =.. [Module,_]. Access =.. [Module,_].
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /**
Each CLP(B) variable belongs to exactly one BDD. Each CLP(B) Each CLP(B) variable belongs to exactly one BDD. Each CLP(B)
variable gets an attribute (in module "clpb") of the form: variable gets an attribute (in module "clpb") of the form:
index_root(Index,Root) ```
index_root(Index,Root)
```
where Index is the variable's unique integer index, and Root is the where Index is the variable's unique integer index, and Root is the
root of the BDD that the variable belongs to. root of the BDD that the variable belongs to.
Each CLP(B) variable also gets an attribute in module clpb_hash: an Each CLP(B) variable also gets an attribute in module `clpb_hash`: an
association table node(LID,HID) -> Node, to keep the BDD reduced. association table node(LID,HID) -> Node, to keep the BDD reduced.
The association table of each variable must be rebuilt on occasion The association table of each variable must be rebuilt on occasion
to remove nodes that are no longer reachable. We rebuild the to remove nodes that are no longer reachable. We rebuild the
association tables of involved variables after BDDs are merged to association tables of involved variables after BDDs are merged to
build a new root. This only serves to reclaim memory: Keeping a build a new root. This only serves to reclaim memory: Keeping a
node in a local table even when it no longer occurs in any BDD does node in a local table even when it no longer occurs in any BDD does
not affect the solver's correctness. However, apply_shortcut/4 not affect the solver's correctness. However, `apply_shortcut/4`
relies on the invariant that every node that occurs in the relevant relies on the invariant that every node that occurs in the relevant
BDDs is also registered in the table of its branching variable. BDDs is also registered in the table of its branching variable.
A root is a logical variable with a single attribute ("clpb_bdd") A root is a logical variable with a single attribute ("clpb\_bdd")
of the form: of the form:
Sat-BDD ```
Sat-BDD
```
where Sat is the SAT formula (in original form) that corresponds to where Sat is the SAT formula (in original form) that corresponds to
BDD. Sat is necessary to rebuild the BDD after variable aliasing, BDD. Sat is necessary to rebuild the BDD after variable aliasing,
and to project all remaining constraints to a list of sat/1 goals. and to project all remaining constraints to a list of `sat/1` goals.
Finally, a BDD is either: Finally, a BDD is either:
*) The integers 0 or 1, denoting false and true, respectively, or * The integers 0 or 1, denoting false and true, respectively, or
*) A node of the form * A node of the form
node(ID, Var, Low, High, Aux) ```
Where ID is the node's unique integer ID, Var is the node(ID, Var, Low, High, Aux)
node's branching variable, and Low and High are the ```
node's low (Var = 0) and high (Var = 1) children. Aux
is a free variable, one for each node, that can be used Where ID is the node's unique integer ID, Var is the
to attach attributes and store intermediate results. node's branching variable, and Low and High are the
node's low (Var = 0) and high (Var = 1) children. Aux
is a free variable, one for each node, that can be used
to attach attributes and store intermediate results.
Variable aliasing is treated as a conjunction of corresponding SAT Variable aliasing is treated as a conjunction of corresponding SAT
formulae. formulae.
You should think of CLP(B) as a potentially vast collection of BDDs You should think of CLP(B) as a potentially vast collection of BDDs
that can range from small to gigantic in size, and which can merge. that can range from small to gigantic in size, and which can merge.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Type checking. Type checking.
@@ -1108,7 +1115,7 @@ indomain(1).
% %
% Examples: % Examples:
% %
% == % ```
% ?- sat(A =< B), Vs = [A,B], sat_count(+[1|Vs], Count). % ?- sat(A =< B), Vs = [A,B], sat_count(+[1|Vs], Count).
% Vs = [A, B], % Vs = [A, B],
% Count = 3, % Count = 3,
@@ -1120,7 +1127,7 @@ indomain(1).
% Vs = [...], % Vs = [...],
% CountOr = 1329227995784915872903807060280344575, % CountOr = 1329227995784915872903807060280344575,
% CountAnd = 1. % CountAnd = 1.
% == % ```
@@ -1248,7 +1255,7 @@ random_bindings(VNum, Node) -->
% linear objective function over Boolean variables Vs with integer % linear objective function over Boolean variables Vs with integer
% coefficients Weights. This predicate assigns 0 and 1 to the % coefficients Weights. This predicate assigns 0 and 1 to the
% variables in Vs such that all stated constraints are satisfied, and % variables in Vs such that all stated constraints are satisfied, and
% Maximum is the maximum of sum(Weight_i*V_i) over all admissible % Maximum is the maximum of `sum(Weight_i*V_i)` over all admissible
% assignments. On backtracking, all admissible assignments that % assignments. On backtracking, all admissible assignments that
% attain the optimum are generated. % attain the optimum are generated.
% %
@@ -1257,10 +1264,10 @@ random_bindings(VNum, Node) -->
% %
% Example: % Example:
% %
% == % ```
% ?- sat(A#B), weighted_maximum([1,2,1], [A,B,C], Maximum). % ?- sat(A#B), weighted_maximum([1,2,1], [A,B,C], Maximum).
% A = 0, B = 1, C = 1, Maximum = 3. % A = 0, B = 1, C = 1, Maximum = 3.
% == % ```
weighted_maximum(Ws, Vars, Max) :- weighted_maximum(Ws, Vars, Max) :-
must_be(list(integer), Ws), must_be(list(integer), Ws),

View File

@@ -1,12 +1,12 @@
/** Predicates for reasoning about files and directories. /** Predicates for reasoning about files and directories.
In this library, directories and files are represented as In this library, directories and files are represented as
*lists of characters*. This is an ideal representation: _lists of characters_. This is an ideal representation:
* Lists of characters can be conveniently reasoned about with DCGs * Lists of characters can be conveniently reasoned about with DCGs
and built-in Prolog predicates from library(lists). This alone and built-in Prolog predicates from `library(lists)`. This alone
is already a very compelling argument to use them. is already a very compelling argument to use them.
* Other Scryer libraries such as library(http/http_open) also already * Other Scryer libraries such as `library(http/http_open)` also already
use lists of characters to represent paths. use lists of characters to represent paths.
* File names are mostly ephemeral, so it is good for efficiency * File names are mostly ephemeral, so it is good for efficiency
that they can quickly allocated transiently on the heap, leaving the that they can quickly allocated transiently on the heap, leaving the
@@ -123,14 +123,14 @@ directory_exists(Directory) :-
%% make_directory(+Directory). %% make_directory(+Directory).
% %
% Succeeds if it creates a new directory named Directory in the current system. % Succeeds if it creates a new directory named Directory in the current system.
% If you want to create a nested directory, use make\_directory\_path/1. % If you want to create a nested directory, use `make_directory_path/1`.
make_directory(Directory) :- make_directory(Directory) :-
must_be(chars, Directory), must_be(chars, Directory),
'$make_directory'(Directory). '$make_directory'(Directory).
%% make_directory_path(+Directory). %% make_directory_path(+Directory).
% %
% Similar to make\_directory/1 but recursively creates directories if they're missing. % Similar to `make_directory/1` but recursively creates directories if they're missing.
% Equivalent to mkdir -p in Unix. % Equivalent to mkdir -p in Unix.
make_directory_path(Directory) :- make_directory_path(Directory) :-
must_be(chars, Directory), must_be(chars, Directory),
@@ -182,8 +182,8 @@ directory_must_exist(Directory, Context) :-
% %
% Dir0 is the current working directory, and the working directory % Dir0 is the current working directory, and the working directory
% is changed to Dir. % is changed to Dir.
%
% Use `working\_directory(Ds, Ds)` to determine the current working directory, % Use `working_directory/2` to determine the current working directory,
% and leave it as is. % and leave it as is.
working_directory(Dir0, Dir) :- working_directory(Dir0, Dir) :-
@@ -220,7 +220,7 @@ path_canonical(Ps, Cs) :-
% %
% For a file File that must exist, it returns a time stamp T with the modification time % For a file File that must exist, it returns a time stamp T with the modification time
% %
% T is a time stamp compatible with library(time). % T is a time stamp compatible with `library(time)`.
file_modification_time(File, T) :- file_modification_time(File, T) :-
file_time_(File, modification, T). file_time_(File, modification, T).
@@ -228,7 +228,7 @@ file_modification_time(File, T) :-
% %
% For a file File that must exist, it returns a time stamp T with the access time % For a file File that must exist, it returns a time stamp T with the access time
% %
% T is a time stamp compatible with library(time). % T is a time stamp compatible with `library(time)`.
file_access_time(File, T) :- file_access_time(File, T) :-
file_time_(File, access, T). file_time_(File, access, T).
@@ -236,7 +236,7 @@ file_access_time(File, T) :-
% %
% For a file File that must exist, it returns a time stamp T with the creation time % For a file File that must exist, it returns a time stamp T with the creation time
% %
% T is a time stamp compatible with library(time). % T is a time stamp compatible with `library(time)`.
file_creation_time(File, T) :- file_creation_time(File, T) :-
file_time_(File, creation, T). file_time_(File, creation, T).
@@ -258,15 +258,19 @@ file_time_(File, Which, T) :-
% %
% Examples: % Examples:
% %
% ?- path_segments("/hello/there", Segments). % ```
% Segments = [[],"hello","there"]. % ?- path_segments("/hello/there", Segments).
% ?- path_segments(Path, ["hello","there"]). % Segments = [[],"hello","there"].
% Path = "hello/there". % ?- path_segments(Path, ["hello","there"]).
% % Path = "hello/there".
% ```
%
% To obtain the platform-specific directory separator, you can use: % To obtain the platform-specific directory separator, you can use:
% %
% ?- path_segments(Separator, ["",""]). % ```
% Separator = "/". % ?- path_segments(Separator, ["",""]).
% Separator = "/".
% ```
path_segments(Path, Segments) :- path_segments(Path, Segments) :-
'$directory_separator'(Sep), '$directory_separator'(Sep),

View File

@@ -5,7 +5,7 @@
/** Make HTTP requests. /** Make HTTP requests.
This library contains the predicate http\_open/3 which allows you to perform HTTP(S) calls. This library contains the predicate `http_open/3` which allows you to perform HTTP(S) calls.
Useful for making API calls, or parsing websites. It uses Hyper underneath. Useful for making API calls, or parsing websites. It uses Hyper underneath.
*/ */
@@ -30,8 +30,10 @@ Useful for making API calls, or parsing websites. It uses Hyper underneath.
% %
% Example: % Example:
% %
% ?- http_open("https://www.example.com", S, []), get_n_chars(S, N, HTML). % ```
% S = '$stream'(0x7fb548001be8), N = 1256, HTML = "<!doctype html>\n<ht ...". % ?- http_open("https://www.example.com", S, []), get_n_chars(S, N, HTML).
% S = '$stream'(0x7fb548001be8), N = 1256, HTML = "<!doctype html>\n<ht ...".
% ```
http_open(Address, Response, Options) :- http_open(Address, Response, Options) :-
parse_http_options(Options, OptionValues), parse_http_options(Options, OptionValues),
( member(method(Method), OptionValues) -> true; Method = get), ( member(method(Method), OptionValues) -> true; Method = get),

View File

@@ -33,9 +33,11 @@ but they're not part of the ISO Prolog standard at the moment.
% For all bindings possible by Generate, Test must be true. % For all bindings possible by Generate, Test must be true.
% %
% In this example, it checks that all numbers are even: % In this example, it checks that all numbers are even:
% %
% ?- Ns = [2,4,6], forall(member(N, Ns), 0 is N mod 2). % ```
% Ns = [2,4,6]. % ?- Ns = [2,4,6], forall(member(N, Ns), 0 is N mod 2).
% Ns = [2,4,6].
% ```
forall(Generate, Test) :- forall(Generate, Test) :-
\+ (Generate, \+ Test). \+ (Generate, \+ Test).
@@ -44,20 +46,25 @@ forall(Generate, Test) :-
%% bb_put(+Key, +Value). %% bb_put(+Key, +Value).
% %
% Sets a global variable named Key (must be an atom) with value Value. % Sets a global variable named Key (must be an atom) with value Value.
% The global variable isn't backtrackable. Check bb\_b\_put/2 for the % The global variable isn't backtrackable. Check `bb_b_put/2` for the
% backtrackable version. % backtrackable version.
% %
% ?- bb_put(city, "Valladolid"). % ```
% true. % ?- bb_put(city, "Valladolid").
% ?- bb_get(city, X). % true.
% X = "Valladolid". % ?- bb_get(city, X).
% In this example one can understand the difference between bb\_put/2 and % X = "Valladolid".
% bb\_b\_put/2: % ```
% %
% ?- bb_put(city, "Valladolid"), (bb_put(city, "Salamanca"), false);(bb_get(city, X)). % In this example one can understand the difference between `bb_put/2` and
% X = "Salamanca". % `bb_b_put/2`:
% ?- bb_put(city, "Valladolid"), (bb_b_put(city, "Salamanca"), false);(bb_get(city, X)). %
% X = "Valladolid". % ```
% ?- bb_put(city, "Valladolid"), (bb_put(city, "Salamanca"), false);(bb_get(city, X)).
% X = "Salamanca".
% ?- bb_put(city, "Valladolid"), (bb_b_put(city, "Salamanca"), false);(bb_get(city, X)).
% X = "Valladolid".
% ```
bb_put(Key, Value) :- bb_put(Key, Value) :-
( atom(Key) -> ( atom(Key) ->
'$store_global_var'(Key, Value) '$store_global_var'(Key, Value)
@@ -69,20 +76,25 @@ bb_put(Key, Value) :-
%% bb_b_put(+Key, +Value). %% bb_b_put(+Key, +Value).
% %
% Sets a global variable named Key (must be an atom) with value Value. % Sets a global variable named Key (must be an atom) with value Value.
% The global variable is backtrackable. Check bb\_put/2 for the % The global variable is backtrackable. Check `bb_put/2` for the
% non-backtrackable version. % non-backtrackable version.
% %
% ?- bb_b_put(city, "Valladolid"). % ```
% true. % ?- bb_b_put(city, "Valladolid").
% ?- bb_get(city, X). % true.
% X = "Valladolid". % ?- bb_get(city, X).
% In this example one can understand the difference between bb\_put/2 and % X = "Valladolid".
% bb\_b\_put/2: % ```
% %
% ?- bb_put(city, "Valladolid"), (bb_put(city, "Salamanca"), false);(bb_get(city, X)). % In this example one can understand the difference between `bb_put/2` and
% X = "Salamanca". % `bb_b_put/2`:
% ?- bb_put(city, "Valladolid"), (bb_b_put(city, "Salamanca"), false);(bb_get(city, X)). %
% X = "Valladolid". % ```
% ?- bb_put(city, "Valladolid"), (bb_put(city, "Salamanca"), false);(bb_get(city, X)).
% X = "Salamanca".
% ?- bb_put(city, "Valladolid"), (bb_b_put(city, "Salamanca"), false);(bb_get(city, X)).
% X = "Valladolid".
% ```
bb_b_put(Key, Value) :- bb_b_put(Key, Value) :-
( atom(Key) -> ( atom(Key) ->
'$store_backtrackable_global_var'(Key, Value) '$store_backtrackable_global_var'(Key, Value)
@@ -119,7 +131,9 @@ call_cleanup(G, C) :- setup_call_cleanup(true, G, C).
% %
% In this example, we use the predicate to always close an open file: % In this example, we use the predicate to always close an open file:
% %
% ?- setup_call_cleanup(open(File, read, Stream), do_something_with_stream(Stream), close(Stream)). % ```
% ?- setup_call_cleanup(open(File, read, Stream), do_something_with_stream(Stream), close(Stream)).
% ```
setup_call_cleanup(S, G, C) :- setup_call_cleanup(S, G, C) :-
'$get_b_value'(B), '$get_b_value'(B),
'$call_with_inference_counting'(call(S)), '$call_with_inference_counting'(call(S)),
@@ -329,13 +343,13 @@ call_nth_nesting(C, ID) :-
%% copy_term_nat(Source, Dest) %% copy_term_nat(Source, Dest)
% %
% Similar to copy\_term/2 but without attribute variables % Similar to `copy_term/2` but without attribute variables
copy_term_nat(Source, Dest) :- copy_term_nat(Source, Dest) :-
'$copy_term_without_attr_vars'(Source, Dest). '$copy_term_without_attr_vars'(Source, Dest).
%% asserta(Module, Rule_Fact). %% asserta(Module, Rule_Fact).
% %
% Similar to asserta/1 but allows specifying a Module % Similar to `asserta/1` but allows specifying a Module
asserta(Module, (Head :- Body)) :- asserta(Module, (Head :- Body)) :-
!, !,
'$asserta'(Module, Head, Body). '$asserta'(Module, Head, Body).
@@ -344,7 +358,7 @@ asserta(Module, Fact) :-
%% assertz(Module, Rule_Fact). %% assertz(Module, Rule_Fact).
% %
% Similar to assertz/1 but allows specifying a Module % Similar to `assertz/1` but allows specifying a Module
assertz(Module, (Head :- Body)) :- assertz(Module, (Head :- Body)) :-
!, !,
'$assertz'(Module, Head, Body). '$assertz'(Module, Head, Body).

View File

@@ -66,12 +66,14 @@ resource_error(Resource, Context) :-
% Relates a list to its length (number of items). It can be used to count the elements of a current list or % Relates a list to its length (number of items). It can be used to count the elements of a current list or
% to create a list full of free variables with N length. % to create a list full of free variables with N length.
% %
% ?- length([a,b,c], 3). % ```
% true. % ?- length([a,b,c], 3).
% ?- length([a,b,c], N). % true.
% N = 3. % ?- length([a,b,c], N).
% ?- length(Xs, 3). % N = 3.
% Xs = [_A, _B, _C]. % ?- length(Xs, 3).
% Xs = [_A, _B, _C].
% ```
length(Xs0, N) :- length(Xs0, N) :-
'$skip_max_list'(M, N, Xs0,Xs), '$skip_max_list'(M, N, Xs0,Xs),
@@ -115,10 +117,11 @@ length_addendum([_|Xs], N, M) :-
% %
% Succeeds when X unifies with an item of the list Xs, which can be at any position. % Succeeds when X unifies with an item of the list Xs, which can be at any position.
% %
% ?- member(X, "hello world"). % ```
% X = h % ?- member(X, "hello world").
% ; ... . % X = h
% % ; ... .
% ```
member(X, [X|_]). member(X, [X|_]).
member(X, [_|Xs]) :- member(X, Xs). member(X, [_|Xs]) :- member(X, Xs).
@@ -126,9 +129,10 @@ member(X, [_|Xs]) :- member(X, Xs).
% %
% Succeeds when the list Xs1 is the list Xs0 without the item X % Succeeds when the list Xs1 is the list Xs0 without the item X
% %
% ?- select(c, "abcd", X). % ```
% X = "abd". % ?- select(c, "abcd", X).
% % X = "abd".
% ```
select(X, [X|Xs], Xs). select(X, [X|Xs], Xs).
select(X, [Y|Xs], [Y|Ys]) :- select(X, Xs, Ys). select(X, [Y|Xs], [Y|Ys]) :- select(X, Xs, Ys).
@@ -136,9 +140,10 @@ select(X, [Y|Xs], [Y|Ys]) :- select(X, Xs, Ys).
% %
% Concatenates a list of lists % Concatenates a list of lists
% %
% ?- append([[1, 2], [3]], Xs). % ```
% Xs = [1, 2, 3]. % ?- append([[1, 2], [3]], Xs).
% % Xs = [1, 2, 3].
% ```
append([], []). append([], []).
append([L0|Ls0], Ls) :- append([L0|Ls0], Ls) :-
append(L0, Rest, Ls), append(L0, Rest, Ls),
@@ -148,15 +153,16 @@ append([L0|Ls0], Ls) :-
% %
% List Xs is the concatenation of Xs0 and Xs1 % List Xs is the concatenation of Xs0 and Xs1
% %
% ?- append([1,2,3], [4,5,6], Xs). % ```
% Xs = [1, 2, 3, 4, 5, 6]. % ?- append([1,2,3], [4,5,6], Xs).
% % Xs = [1, 2, 3, 4, 5, 6].
% ```
append([], R, R). append([], R, R).
append([X|L], R, [X|S]) :- append(L, R, S). append([X|L], R, [X|S]) :- append(L, R, S).
%% memberchk(?X, +Xs). %% memberchk(?X, +Xs).
% %
% This predicate is similar to member/2, but it only provides a single answer % This predicate is similar to `member/2`, but it only provides a single answer
memberchk(X, Xs) :- member(X, Xs), !. memberchk(X, Xs) :- member(X, Xs), !.
%% reverse(?Xs, ?Ys). %% reverse(?Xs, ?Ys).
@@ -179,9 +185,10 @@ reverse([_|Xs], [Y1|Ys], YsPreludeRev, Xss) :-
% %
% This is a metapredicate that applies predicate to each element of the list Xs0 % This is a metapredicate that applies predicate to each element of the list Xs0
% %
% ?- maplist(write, [1,2,3]). % ```
% 123 true. % ?- maplist(write, [1,2,3]).
% % 123 true.
% ```
maplist(_, []). maplist(_, []).
maplist(Cont1, [E1|E1s]) :- maplist(Cont1, [E1|E1s]) :-
call(Cont1, E1), call(Cont1, E1),
@@ -191,9 +198,10 @@ maplist(Cont1, [E1|E1s]) :-
% %
% This is a metapredicate that applies predicate to each element of the lists Xs0 and Xs1. % This is a metapredicate that applies predicate to each element of the lists Xs0 and Xs1.
% %
% ?- maplist(length, ["hello", "prolog", "marseille"], Xs1). % ```
% Xs1 = [5,6,9]. % ?- maplist(length, ["hello", "prolog", "marseille"], Xs1).
% % Xs1 = [5,6,9].
% ```
maplist(_, [], []). maplist(_, [], []).
maplist(Cont2, [E1|E1s], [E2|E2s]) :- maplist(Cont2, [E1|E1s], [E2|E2s]) :-
call(Cont2, E1, E2), call(Cont2, E1, E2),
@@ -251,8 +259,10 @@ maplist(Cont, [E1|E1s], [E2|E2s], [E3|E3s], [E4|E4s], [E5|E5s], [E6|E6s], [E7|E7
% %
% Takes a lists of numbers and unifies Sum with the result of summing all the elements of the list. % Takes a lists of numbers and unifies Sum with the result of summing all the elements of the list.
% %
% ?- sum_list([2,2,2], 6). % ```
% true. % ?- sum_list([2,2,2], 6).
% true.
% ```
sum_list(Ls, S) :- sum_list(Ls, S) :-
foldl(lists:sum_, Ls, 0, S). foldl(lists:sum_, Ls, 0, S).
@@ -274,12 +284,15 @@ same_length([_|As], [_|Bs]) :-
% %
% For example, if we define sum_ as: % For example, if we define sum_ as:
% %
% sum_(L, S0, S) :- S is S0 + L. % ```
% sum_(L, S0, S) :- S is S0 + L.
% ```
% %
% Then we can define sum\_list/2 as the following: % Then we can define `sum_list/2` as the following:
%
% sum_list(Ls, S) :- foldl(sum_, Ls, 0, S).
% %
% ```
% sum_list(Ls, S) :- foldl(sum_, Ls, 0, S).
% ```
foldl(Goal_3, Ls, A0, A) :- foldl(Goal_3, Ls, A0, A) :-
foldl_(Ls, Goal_3, A0, A). foldl_(Ls, Goal_3, A0, A).
@@ -291,7 +304,7 @@ foldl_([L|Ls], G_3, A0, A) :-
%% foldl(+Predicate, ?Ls0, ?Ls1, +A0, ?A). %% foldl(+Predicate, ?Ls0, ?Ls1, +A0, ?A).
% %
% Same as foldl/4 but with an extra list % Same as `foldl/4` but with an extra list
foldl(Goal_4, Xs, Ys, A0, A) :- foldl(Goal_4, Xs, Ys, A0, A) :-
foldl_(Xs, Ys, Goal_4, A0, A). foldl_(Xs, Ys, Goal_4, A0, A).
@@ -305,9 +318,10 @@ foldl_([X|Xs], [Y|Ys], G_4, A0, A) :-
% %
% If Ls is a list of lists, Ts contains the transposition % If Ls is a list of lists, Ts contains the transposition
% %
% ?- transpose([[1,1],[2,2]], Ts). % ```
% Ts = [[1,2],[1,2]]. % ?- transpose([[1,1],[2,2]], Ts).
% % Ts = [[1,2],[1,2]].
% ```
transpose(Ls, Ts) :- transpose(Ls, Ts) :-
lists_transpose(Ls, Ts). lists_transpose(Ls, Ts).
@@ -325,9 +339,10 @@ list_first_rest([L|Ls], L, Ls).
% %
% Takes a list Ls0 and returns a list Set that doesn't contain any repeated element % Takes a list Ls0 and returns a list Set that doesn't contain any repeated element
% %
% ?- list_to_set([2,3,4,4,1,2], Set). % ```
% Set = [2,3,4,1]. % ?- list_to_set([2,3,4,4,1,2], Set).
% % Set = [2,3,4,1].
% ```
list_to_set(Ls0, Ls) :- list_to_set(Ls0, Ls) :-
maplist(lists:with_var, Ls0, LVs0), maplist(lists:with_var, Ls0, LVs0),
keysort(LVs0, LVs), keysort(LVs0, LVs),
@@ -359,8 +374,10 @@ unify_same(E-V, Prev-Var, E-V) :-
% %
% Succeeds if in the N position of the list Ls, we found the element E. The elements start counting from zero. % Succeeds if in the N position of the list Ls, we found the element E. The elements start counting from zero.
% %
% ?- nth0(2, [1,2,3,4], 3). % ```
% true. % ?- nth0(2, [1,2,3,4], 3).
% true.
% ```
nth0(N, Es0, E) :- nth0(N, Es0, E) :-
nonvar(N), nonvar(N),
'$skip_max_list'(Skip, N, Es0,Es1), '$skip_max_list'(Skip, N, Es0,Es1),
@@ -399,8 +416,10 @@ nth0_el(N0,N, _,E, [E0|Es0]) :-
% %
% Succeeds if in the N position of the list Ls, we found the element E. The elements start counting from one. % Succeeds if in the N position of the list Ls, we found the element E. The elements start counting from one.
% %
% ?- nth1(2, [1,2,3,4], 2). % ```
% true. % ?- nth1(2, [1,2,3,4], 2).
% true.
% ```
nth1(N, Es0, E) :- nth1(N, Es0, E) :-
N \== 0, N \== 0,
nth0(N, [_|Es0], E), nth0(N, [_|Es0], E),
@@ -419,8 +438,10 @@ skipn(0, Es,Es, Xs,Xs).
% %
% Succeeds if in the N position of the list Ls, we found the element E and the rest of the list is Rs. The elements start counting from zero. % Succeeds if in the N position of the list Ls, we found the element E and the rest of the list is Rs. The elements start counting from zero.
% %
% ?- nth0(2, [1,2,3,4], 3, [1,2,4]). % ```
% true. % ?- nth0(2, [1,2,3,4], 3, [1,2,4]).
% true.
% ```
nth0(N, Es0, E, Es) :- nth0(N, Es0, E, Es) :-
integer(N), integer(N),
N >= 0, N >= 0,
@@ -449,8 +470,10 @@ nth0_elx(N0,N, E0,E, [E1|Es0], [E0|Es]) :-
% %
% Succeeds if in the N position of the list Ls, we found the element E and the rest of the list is Rs. The elements start counting from one. % Succeeds if in the N position of the list Ls, we found the element E and the rest of the list is Rs. The elements start counting from one.
% %
% ?- nth1(2, [1,2,3,4], 2, [1,3,4]). % ```
% true. % ?- nth1(2, [1,2,3,4], 2, [1,3,4]).
% true.
% ```
nth1(N, Es0, E, Es) :- nth1(N, Es0, E, Es) :-
N \== 0, N \== 0,
nth0(N, [_|Es0], E, [_|Es]), nth0(N, [_|Es0], E, [_|Es]),
@@ -478,7 +501,7 @@ list_min_(N, Min0, Min) :-
% %
% True when Xs is a permutation of Ys. This can solve for Ys given % True when Xs is a permutation of Ys. This can solve for Ys given
% Xs or Xs given Ys, or even enumerate Xs and Ys together. The % Xs or Xs given Ys, or even enumerate Xs and Ys together. The
% predicate permutation/2 is primarily intended to generate % predicate `permutation/2` is primarily intended to generate
% permutations. Note that a list of length N has N! permutations, % permutations. Note that a list of length N has N! permutations,
% and unbounded permutation generation becomes prohibitively % and unbounded permutation generation becomes prohibitively
% expensive, even for rather short lists (10! = 3,628,800). % expensive, even for rather short lists (10! = 3,628,800).
@@ -486,12 +509,14 @@ list_min_(N, Min0, Min) :-
% The example below illustrates that Xs and Ys being proper lists % The example below illustrates that Xs and Ys being proper lists
% is not a sufficient condition to use the above replacement. % is not a sufficient condition to use the above replacement.
% %
% ?- permutation([1,2], [X,Y]). % ```
% X = 1, Y = 2 % ?- permutation([1,2], [X,Y]).
% ; X = 2, Y = 1 % X = 1, Y = 2
% ; false. % ; X = 2, Y = 1
% ; false.
% ```
% %
% Throws type\_error(list, Arg) if either argument is not a proper % Throws `type_error(list, Arg)` if either argument is not a proper
% or partial list. % or partial list.
permutation(Xs, Ys) :- permutation(Xs, Ys) :-

View File

@@ -57,22 +57,22 @@
/** Ordered set manipulation /** Ordered set manipulation
Ordered sets are lists with unique elements sorted to the standard order Ordered sets are lists with unique elements sorted to the standard order
of terms (see sort/2). Exploiting ordering, many of the set operations of terms (see `sort/2`). Exploiting ordering, many of the set operations
can be expressed in order N rather than N^2 when dealing with unordered can be expressed in order N rather than N^2 when dealing with unordered
sets that may contain duplicates. The library(ordsets) is available in a sets that may contain duplicates. The library(ordsets) is available in a
number of Prolog implementations. Our predicates are designed to be number of Prolog implementations. Our predicates are designed to be
compatible with common practice in the Prolog community. compatible with common practice in the Prolog community.
Some of these predicates match directly to corresponding list Some of these predicates match directly to corresponding list
operations. It is advised to use the versions from this library to make operations. It is advised to use the versions from this library to make
clear you are operating on ordered sets. An exception is member/2. See clear you are operating on ordered sets. An exception is `member/2`. See
ord\_memberchk/2. `ord_memberchk/2`.
The ordsets library is based on the standard order of terms. This The ordsets library is based on the standard order of terms. This
implies it can handle all Prolog terms, including variables. Note implies it can handle all Prolog terms, including variables. Note
however, that the ordering is not stable if a term inside the set is however, that the ordering is not stable if a term inside the set is
further instantiated. Also note that variable ordering changes if further instantiated. Also note that variable ordering changes if
variables in the set are unified with each other or a variable in the variables in the set are unified with each other or a variable in the
set is unified with a variable that is `older' than the newest variable set is unified with a variable that is _older_ than the newest variable
in the set. In practice, this implies that it is allowed to use in the set. In practice, this implies that it is allowed to use
member(X, OrdSet) on an ordered set that holds variables only if X is a member(X, OrdSet) on an ordered set that holds variables only if X is a
fresh variable. In other cases one should cease using it as an ordset fresh variable. In other cases one should cease using it as an ordset
@@ -84,8 +84,8 @@ because the order it relies on may have been changed.
% True if Term is an ordered set. All predicates in this library % True if Term is an ordered set. All predicates in this library
% expect ordered sets as input arguments. Failing to fullfil this % expect ordered sets as input arguments. Failing to fullfil this
% assumption results in undefined behaviour. Typically, ordered % assumption results in undefined behaviour. Typically, ordered
% sets are created by predicates from this library, sort/2 or % sets are created by predicates from this library, `sort/2` or
% setof/3. % `setof/3`.
is_ordset(Term) :- is_ordset(Term) :-
'$skip_max_list'(_, _, Term, Tail), Tail == [], %% is_list(Term), '$skip_max_list'(_, _, Term, Tail), Tail == [], %% is_list(Term),
@@ -112,7 +112,7 @@ ord_empty([]).
%% ord_seteq(+Set1, +Set2) is semidet. %% ord_seteq(+Set1, +Set2) is semidet.
% %
% True if Set1 and Set2 have the same elements. As both are % True if Set1 and Set2 have the same elements. As both are
% canonical sorted lists, this is the same as ==/2. % canonical sorted lists, this is the same as `==/2`.
ord_seteq(Set1, Set2) :- ord_seteq(Set1, Set2) :-
Set1 == Set2. Set1 == Set2.
@@ -148,7 +148,7 @@ ord_intersect__(>, H1, T1, _H2, T2) :-
%% ord_disjoint(+Set1, +Set2) is semidet. %% ord_disjoint(+Set1, +Set2) is semidet.
% %
% True if Set1 and Set2 have no common elements. This is the % True if Set1 and Set2 have no common elements. This is the
% negation of ord\_intersect/2. % negation of `ord_intersect/2`.
ord_disjoint(Set1, Set2) :- ord_disjoint(Set1, Set2) :-
\+ ord_intersect(Set1, Set2). \+ ord_intersect(Set1, Set2).
@@ -158,7 +158,7 @@ ord_disjoint(Set1, Set2) :-
% %
% Intersection holds the common elements of Set1 and Set2. % Intersection holds the common elements of Set1 and Set2.
% %
% This predicate is **deprecated**. Use ord\_intersection/3 % This predicate is *deprecated*. Use `ord_intersection/3`
ord_intersect(Set1, Set2, Intersection) :- ord_intersect(Set1, Set2, Intersection) :-
oset_int(Set1, Set2, Intersection). oset_int(Set1, Set2, Intersection).
@@ -188,7 +188,7 @@ l_int([_-H|T], S0, S) :-
%% ord_intersection(+Set1, +Set2, -Intersection) is det. %% ord_intersection(+Set1, +Set2, -Intersection) is det.
% %
% Intersection holds the common elements of Set1 and Set2. Uses % Intersection holds the common elements of Set1 and Set2. Uses
% ord\_disjoint/2 if Intersection is bound to `[]` on entry. % `ord_disjoint/2` if Intersection is bound to `[]` on entry.
ord_intersection(Set1, Set2, Intersection) :- ord_intersection(Set1, Set2, Intersection) :-
( Intersection == [] ( Intersection == []
@@ -201,7 +201,7 @@ ord_intersection(Set1, Set2, Intersection) :-
% %
% Intersection and difference between two ordered sets. % Intersection and difference between two ordered sets.
% Intersection is the intersection between Set1 and Set2, while % Intersection is the intersection between Set1 and Set2, while
% Difference is defined by ord\_subtract(Set2, Set1, Difference). % Difference is defined by `ord_subtract(Set2, Set1, Difference)`.
ord_intersection([], L, [], L) :- !. ord_intersection([], L, [], L) :- !.
ord_intersection([_|_], [], [], []) :- !. ord_intersection([_|_], [], [], []) :- !.
@@ -220,7 +220,7 @@ ord_intersection2(>, H1, T1, H2, T2, Intersection, [H2|HDiff]) :-
%% ord_add_element(+Set1, +Element, ?Set2) is det. %% ord_add_element(+Set1, +Element, ?Set2) is det.
% %
% Insert an element into the set. This is the same as % Insert an element into the set. This is the same as
% ord\_union(Set1, [Element], Set2). % `ord_union(Set1, [Element], Set2)`.
ord_add_element(Set1, Element, Set2) :- ord_add_element(Set1, Element, Set2) :-
oset_addel(Set1, Element, Set2). oset_addel(Set1, Element, Set2).
@@ -229,7 +229,7 @@ ord_add_element(Set1, Element, Set2) :-
%% ord_del_element(+Set, +Element, -NewSet) is det. %% ord_del_element(+Set, +Element, -NewSet) is det.
% %
% Delete an element from an ordered set. This is the same as % Delete an element from an ordered set. This is the same as
% ord\_subtract(Set, [Element], NewSet). % `ord_subtract(Set, [Element], NewSet)`.
ord_del_element(Set, Element, NewSet) :- ord_del_element(Set, Element, NewSet) :-
oset_delel(Set, Element, NewSet). oset_delel(Set, Element, NewSet).
@@ -237,13 +237,13 @@ ord_del_element(Set, Element, NewSet) :-
%% ord_selectchk(+Item, ?Set1, ?Set2) is semidet. %% ord_selectchk(+Item, ?Set1, ?Set2) is semidet.
% %
% Selectchk/3, specialised for ordered sets. Is true when % `selectchk/3`, specialised for ordered sets. Is true when
% select(Item, Set1, Set2) and Set1, Set2 are both sorted lists % select(Item, Set1, Set2) and Set1, Set2 are both sorted lists
% without duplicates. This implementation is only expected to work % without duplicates. This implementation is only expected to work
% for Item ground and either Set1 or Set2 ground. The "chk" suffix % for Item ground and either Set1 or Set2 ground. The "chk" suffix
% is meant to remind you of memberchk/2, which also expects its % is meant to remind you of `memberchk/2`, which also expects its
% first argument to be ground. ord\_selectchk(X, S, T) => % first argument to be ground. `ord_selectchk(X, S, T) =>
% ord\_memberchk(X, S) & \\+ ord\_memberchk(X, T). % ord_memberchk(X, S) & \+ ord_memberchk(X, T).`
% %
% Author: Richard O'Keefe % Author: Richard O'Keefe
@@ -263,13 +263,13 @@ ord_selectchk(Item, [Item|Set1], Set1) :-
% %
% True if Element is a member of OrdSet, compared using ==. Note % True if Element is a member of OrdSet, compared using ==. Note
% that _enumerating_ elements of an ordered set can be done using % that _enumerating_ elements of an ordered set can be done using
% member/2. % `member/2`.
% %
% Some Prolog implementations also provide ord\_member/2, with the % Some Prolog implementations also provide `ord_member/2`, with the
% same semantics as ord\_memberchk/2. We believe that having a % same semantics as `ord_memberchk/2`. We believe that having a
% semidet ord\_member/2 is unacceptably inconsistent with the \*\_chk % semidet `ord_member/2` is unacceptably inconsistent with the \*\_chk
% convention. Portable code should use ord\_memberchk/2 or % convention. Portable code should use `ord_memberchk/2` or
% member/2. % `member/2`.
% %
% Author: Richard O'Keefe % Author: Richard O'Keefe
@@ -356,8 +356,8 @@ ord_union(Set1, Set2, Union) :-
%% ord_union(+Set1, +Set2, -Union, -New) is det. %% ord_union(+Set1, +Set2, -Union, -New) is det.
% %
% True iff ord\_union(Set1, Set2, Union) and % True iff `ord_union(Set1, Set2, Union)` and
% ord\_subtract(Set2, Set1, New). % `ord_subtract(Set2, Set1, New)`.
ord_union([], Set2, Set2, Set2). ord_union([], Set2, Set2, Set2).
ord_union([H|T], Set2, Union, New) :- ord_union([H|T], Set2, Union, New) :-
@@ -389,14 +389,18 @@ ord_union_2([H|T], H2, T2, Union, New) :-
% sequence below (but the actual implementation requires only a % sequence below (but the actual implementation requires only a
% single scan). % single scan).
% %
% ord_union(Set1, Set2, Union), % ```
% ord_intersection(Set1, Set2, Intersection), % ord_union(Set1, Set2, Union),
% ord_subtract(Union, Intersection, Difference). % ord_intersection(Set1, Set2, Intersection),
% ord_subtract(Union, Intersection, Difference).
% ```
% %
% For example: % For example:
% %
% ?- ord_symdiff([1,2], [2,3], X). % ```
% X = [1,3]. % ?- ord_symdiff([1,2], [2,3], X).
% X = [1,3].
% ```
ord_symdiff([], Set2, Set2). ord_symdiff([], Set2, Set2).
ord_symdiff([H1|T1], Set2, Difference) :- ord_symdiff([H1|T1], Set2, Difference) :-

View File

@@ -30,9 +30,9 @@ random(R) :-
% %
% Generates a random integer number between Lower (inclusive) and Upper (exclusive). % Generates a random integer number between Lower (inclusive) and Upper (exclusive).
% %
% Throws instantiation\_error if Lower or Upper are variables. % Throws `instantiation_error` if Lower or Upper are variables.
% %
% Throws type\_error if Lower or Upper aren't integers. % Throws `type_error` if Lower or Upper aren't integers.
random_integer(Lower, Upper, R) :- random_integer(Lower, Upper, R) :-
var(R), var(R),
( (var(Lower) ; var(Upper)) -> ( (var(Lower) ; var(Upper)) ->

View File

@@ -1,6 +1,6 @@
/** /**
Predicates for handling network sockets, both as a server and as a client. Predicates for handling network sockets, both as a server and as a client.
As a server, you should open a socket an call socket\_server\_accept/4 to get a stream for each connection. As a server, you should open a socket an call `socket_server_accept/4` to get a stream for each connection.
As a client, you should just open a socket and you will receive a stream. As a client, you should just open a socket and you will receive a stream.
In both cases, with a stream, you can use the usual predicates to read and write to the stream. In both cases, with a stream, you can use the usual predicates to read and write to the stream.
*/ */
@@ -18,10 +18,10 @@ In both cases, with a stream, you can use the usual predicates to read and write
% %
% The following options are available: % The following options are available:
% %
% * alias(+Alias): Set an alias to the stream % * `alias(+Alias)`: Set an alias to the stream
% * eof_action(+Action): Defined what happens if the end of the stream is reached. Values: `error`, `eof_code` and `reset`. % * `eof_action(+Action)`: Defined what happens if the end of the stream is reached. Values: `error`, `eof_code` and `reset`.
% * reposition(+Boolean): Specifies whether repositioning is required for the stream. `false` is the default. % * `reposition(+Boolean)`: Specifies whether repositioning is required for the stream. `false` is the default.
% * type(+Type): Type can be `text` or `binary`. Defines the type of the stream, if it's optimized for plain text % * `type(+Type)`: Type can be `text` or `binary`. Defines the type of the stream, if it's optimized for plain text
% or just binary % or just binary
% %
socket_client_open(Addr, Stream, Options) :- socket_client_open(Addr, Stream, Options) :-
@@ -47,7 +47,7 @@ socket_client_open(Addr, Stream, Options) :-
%% socket_server_open(+Addr, -ServerSocket). %% socket_server_open(+Addr, -ServerSocket).
% %
% Open a server socket, returning a ServerSocket. Use that ServerSocket to accept incoming connections in % Open a server socket, returning a ServerSocket. Use that ServerSocket to accept incoming connections in
% socket\_server\_accept/4. Addr must satisfy `Addr = Address:Port`. Depending on the operating system % `socket_server_accept/4`. Addr must satisfy `Addr = Address:Port`. Depending on the operating system
% configuration, some ports might be reserved for superusers. % configuration, some ports might be reserved for superusers.
socket_server_open(Addr, ServerSocket) :- socket_server_open(Addr, ServerSocket) :-
must_be(var, ServerSocket), must_be(var, ServerSocket),
@@ -67,10 +67,10 @@ socket_server_open(Addr, ServerSocket) :-
% %
% The following options are available: % The following options are available:
% %
% * alias(+Alias): Set an alias to the stream % * `alias(+Alias)`: Set an alias to the stream
% * eof_action(+Action): Defined what happens if the end of the stream is reached. Values: `error`, `eof_code` and `reset`. % * `eof_action(+Action)`: Defined what happens if the end of the stream is reached. Values: `error`, `eof_code` and `reset`.
% * reposition(+Boolean): Specifies whether repositioning is required for the stream. `false` is the default. % * `reposition(+Boolean)`: Specifies whether repositioning is required for the stream. `false` is the default.
% * type(+Type): Type can be `text` or `binary`. Defines the type of the stream, if it's optimized for plain text % * `type(+Type)`: Type can be `text` or `binary`. Defines the type of the stream, if it's optimized for plain text
% or just binary % or just binary
% %
socket_server_accept(ServerSocket, Client, Stream, Options) :- socket_server_accept(ServerSocket, Client, Stream, Options) :-

View File

@@ -61,14 +61,14 @@ neighbours of each vertex are also in standard order (as produced by
sort). This form is convenient for many calculations. sort). This form is convenient for many calculations.
A new UGraph from raw data can be created using A new UGraph from raw data can be created using
vertices\_edges\_to\_ugraph/3. `vertices_edges_to_ugraph/3`.
Adapted to support some of the functionality of the SICStus ugraphs Adapted to support some of the functionality of the SICStus ugraphs
library by Vitor Santos Costa. library by Vitor Santos Costa.
Ported from YAP 5.0.1 to SWI-Prolog by Jan Wielemaker. Ported from YAP 5.0.1 to SWI-Prolog by Jan Wielemaker.
Ported from SWI-Prolog to Scryer by Adrián Arroyo Calle Ported from SWI-Prolog to Scryer by [Adrián Arroyo Calle](https://adrianistan.eu)
License: BSD-2 or Artistic 2.0 License: BSD-2 or Artistic 2.0
*/ */
@@ -81,8 +81,10 @@ License: BSD-2 or Artistic 2.0
% %
% Unify Vertices with all vertices appearing in Graph. Example: % Unify Vertices with all vertices appearing in Graph. Example:
% %
% ?- vertices([1-[3,5],2-[4],3-[],4-[5],5-[]], L). % ```
% L = [1, 2, 3, 4, 5] % ?- vertices([1-[3,5],2-[4],3-[],4-[5],5-[]], L).
% L = [1, 2, 3, 4, 5]
% ```
vertices([], []) :- !. vertices([], []) :- !.
vertices([Vertex-_|Graph], [Vertex|Vertices]) :- vertices([Vertex-_|Graph], [Vertex|Vertices]) :-
@@ -97,14 +99,18 @@ vertices([Vertex-_|Graph], [Vertex|Vertices]) :-
% edges will appear in Vertices but not in Edges. Moreover, it is % edges will appear in Vertices but not in Edges. Moreover, it is
% sufficient for a vertice to appear in Edges. % sufficient for a vertice to appear in Edges.
% %
% ?- vertices_edges_to_ugraph([],[1-3,2-4,4-5,1-5], L). % ```
% L = [1-[3,5], 2-[4], 3-[], 4-[5], 5-[]] % ?- vertices_edges_to_ugraph([],[1-3,2-4,4-5,1-5], L).
% % L = [1-[3,5], 2-[4], 3-[], 4-[5], 5-[]]
% ```
%
% In this case all vertices are defined implicitly. The next % In this case all vertices are defined implicitly. The next
% example shows three unconnected vertices: % example shows three unconnected vertices:
% %
% ?- vertices_edges_to_ugraph([6,7,8],[1-3,2-4,4-5,1-5], L). % ```
% L = [1-[3,5], 2-[4], 3-[], 4-[5], 5-[], 6-[], 7-[], 8-[]] % ?- vertices_edges_to_ugraph([6,7,8],[1-3,2-4,4-5,1-5], L).
% L = [1-[3,5], 2-[4], 3-[], 4-[5], 5-[], 6-[], 7-[], 8-[]]
% ```
vertices_edges_to_ugraph(Vertices, Edges, Graph) :- vertices_edges_to_ugraph(Vertices, Edges, Graph) :-
sort(Edges, EdgeSet), sort(Edges, EdgeSet),
@@ -119,8 +125,10 @@ vertices_edges_to_ugraph(Vertices, Edges, Graph) :-
% Unify NewGraph with a new graph obtained by adding the list of % Unify NewGraph with a new graph obtained by adding the list of
% Vertices to Graph. Example: % Vertices to Graph. Example:
% %
% ?- add_vertices([1-[3,5],2-[]], [0,1,2,9], NG). % ```
% NG = [0-[], 1-[3,5], 2-[], 9-[]] % ?- add_vertices([1-[3,5],2-[]], [0,1,2,9], NG).
% NG = [0-[], 1-[3,5], 2-[], 9-[]]
% ```
% replace with real msort/2 when available % replace with real msort/2 when available
msort_(List, Sorted) :- msort_(List, Sorted) :-
@@ -158,10 +166,12 @@ add_empty_vertices([V|G], [V-[]|NG]) :-
% Vertices and all the edges that start from or go to a vertex in % Vertices and all the edges that start from or go to a vertex in
% Vertices to the Graph. Example: % Vertices to the Graph. Example:
% %
% ?- del_vertices([1-[3,5],2-[4],3-[],4-[5],5-[],6-[],7-[2,6],8-[]], % ```
% [2,1], % ?- del_vertices([1-[3,5],2-[4],3-[],4-[5],5-[],6-[],7-[2,6],8-[]],
% NL). % [2,1],
% NL = [3-[],4-[5],5-[],6-[],7-[6],8-[]] % NL).
% NL = [3-[],4-[5],5-[],6-[],7-[6],8-[]]
% ```
del_vertices(Graph, Vertices, NewGraph) :- del_vertices(Graph, Vertices, NewGraph) :-
sort(Vertices, V1), % JW: was msort sort(Vertices, V1), % JW: was msort
@@ -195,12 +205,14 @@ split_on_del_vertices(=, _, _, [_|Vs], Vs, _, NG, NG).
% Unify NewGraph with a new graph obtained by adding the list of Edges % Unify NewGraph with a new graph obtained by adding the list of Edges
% to Graph. Example: % to Graph. Example:
% %
% ?- add_edges([1-[3,5],2-[4],3-[],4-[5], % ```
% 5-[],6-[],7-[],8-[]], % ?- add_edges([1-[3,5],2-[4],3-[],4-[5],
% [1-6,2-3,3-2,5-7,3-2,4-5], % 5-[],6-[],7-[],8-[]],
% NL). % [1-6,2-3,3-2,5-7,3-2,4-5],
% NL = [1-[3,5,6], 2-[3,4], 3-[2], 4-[5], % NL).
% 5-[7], 6-[], 7-[], 8-[]] % NL = [1-[3,5,6], 2-[3,4], 3-[2], 4-[5],
% 5-[7], 6-[], 7-[], 8-[]]
% ```
add_edges(Graph, Edges, NewGraph) :- add_edges(Graph, Edges, NewGraph) :-
p_to_s_graph(Edges, G1), p_to_s_graph(Edges, G1),
@@ -210,8 +222,10 @@ add_edges(Graph, Edges, NewGraph) :-
% %
% NewGraph is the union of Graph1 and Graph2. Example: % NewGraph is the union of Graph1 and Graph2. Example:
% %
% ?- ugraph_union([1-[2],2-[3]],[2-[4],3-[1,2,4]],L). % ```
% L = [1-[2], 2-[3,4], 3-[1,2,4]] % ?- ugraph_union([1-[2],2-[3]],[2-[4],3-[1,2,4]],L).
% L = [1-[2], 2-[3,4], 3-[1,2,4]]
% ```
ugraph_union(Set1, [], Set1) :- !. ugraph_union(Set1, [], Set1) :- !.
ugraph_union([], Set2, Set2) :- !. ugraph_union([], Set2, Set2) :- !.
@@ -232,10 +246,12 @@ ugraph_union(>, Head1, Tail1, Head2, Tail2, [Head2|Union]) :-
% Unify NewGraph with a new graph obtained by removing the list of % Unify NewGraph with a new graph obtained by removing the list of
% Edges from Graph. Notice that no vertices are deleted. Example: % Edges from Graph. Notice that no vertices are deleted. Example:
% %
% ?- del_edges([1-[3,5],2-[4],3-[],4-[5],5-[],6-[],7-[],8-[]], % ```
% [1-6,2-3,3-2,5-7,3-2,4-5,1-3], % ?- del_edges([1-[3,5],2-[4],3-[],4-[5],5-[],6-[],7-[],8-[]],
% NL). % [1-6,2-3,3-2,5-7,3-2,4-5,1-3],
% NL = [1-[5],2-[4],3-[],4-[],5-[],6-[],7-[],8-[]] % NL).
% NL = [1-[5],2-[4],3-[],4-[],5-[],6-[],7-[],8-[]]
% ```
del_edges(Graph, Edges, NewGraph) :- del_edges(Graph, Edges, NewGraph) :-
p_to_s_graph(Edges, G1), p_to_s_graph(Edges, G1),
@@ -243,7 +259,7 @@ del_edges(Graph, Edges, NewGraph) :-
%% graph_subtract(+Set1, +Set2, ?Difference) %% graph_subtract(+Set1, +Set2, ?Difference)
% %
% Is based on ord_subtract % Is based on `ord_subtract/3`
graph_subtract(Set1, [], Set1) :- !. graph_subtract(Set1, [], Set1) :- !.
graph_subtract([], _, []). graph_subtract([], _, []).
@@ -263,8 +279,10 @@ graph_subtract(>, Head1, Tail1, _, Tail2, Difference) :-
% %
% Unify Edges with all edges appearing in Graph. Example: % Unify Edges with all edges appearing in Graph. Example:
% %
% ?- edges([1-[3,5],2-[4],3-[],4-[5],5-[]], L). % ```
% L = [1-3, 1-5, 2-4, 4-5] % ?- edges([1-[3,5],2-[4],3-[],4-[5],5-[]], L).
% L = [1-3, 1-5, 2-4, 4-5]
% ```
edges(Graph, Edges) :- edges(Graph, Edges) :-
s_to_p_graph(Graph, Edges). s_to_p_graph(Graph, Edges).
@@ -309,8 +327,10 @@ s_to_p_graph([Neib|Neibs], Vertex, [Vertex-Neib|P], Rest_P) :-
% Generate the graph Closure as the transitive closure of Graph. % Generate the graph Closure as the transitive closure of Graph.
% Example: % Example:
% %
% ?- transitive_closure([1-[2,3],2-[4,5],4-[6]],L). % ```
% L = [1-[2,3,4,5,6], 2-[4,5,6], 4-[6]] % ?- transitive_closure([1-[2,3],2-[4,5],4-[6]],L).
% L = [1-[2,3,4,5,6], 2-[4,5,6], 4-[6]]
% ```
transitive_closure(Graph, Closure) :- transitive_closure(Graph, Closure) :-
warshall(Graph, Graph, Closure). warshall(Graph, Graph, Closure).
@@ -336,12 +356,14 @@ warshall([], _, _, []).
% %
% Unify NewGraph with a new graph obtained from Graph by replacing % Unify NewGraph with a new graph obtained from Graph by replacing
% all edges of the form V1-V2 by edges of the form V2-V1. The cost % all edges of the form V1-V2 by edges of the form V2-V1. The cost
% is O(|V|*log(|V|)). Notice that an undirected graph is its own % is O(|V|\*log(|V|)). Notice that an undirected graph is its own
% transpose. Example: % transpose. Example:
% %
% ?- transpose([1-[3,5],2-[4],3-[],4-[5], % ```
% 5-[],6-[],7-[],8-[]], NL). % ?- transpose([1-[3,5],2-[4],3-[],4-[5],
% NL = [1-[],2-[],3-[1],4-[2],5-[1,4],6-[],7-[],8-[]] % 5-[],6-[],7-[],8-[]], NL).
% NL = [1-[],2-[],3-[1],4-[2],5-[1,4],6-[],7-[],8-[]]
% ```
transpose_ugraph(Graph, NewGraph) :- transpose_ugraph(Graph, NewGraph) :-
edges(Graph, Edges), edges(Graph, Edges),
@@ -358,8 +380,10 @@ flip_edges([Key-Val|Pairs], [Val-Key|Flipped]) :-
% Compose NewGraph by connecting the _drains_ of LeftGraph to the % Compose NewGraph by connecting the _drains_ of LeftGraph to the
% _sources_ of RightGraph. Example: % _sources_ of RightGraph. Example:
% %
% ?- compose([1-[2],2-[3]],[2-[4],3-[1,2,4]],L). % ```
% L = [1-[4], 2-[1,2,4], 3-[]] % ?- compose([1-[2],2-[3]],[2-[4],3-[1,2,4]],L).
% L = [1-[4], 2-[1,2,4], 3-[]]
% ```
compose(G1, G2, Composition) :- compose(G1, G2, Composition) :-
vertices(G1, V1), vertices(G1, V1),
@@ -401,8 +425,10 @@ compose1(=, V1, Vs1, V1, N2, G2, SoFar, Comp) :-
% acyclic. In the example we show how topological sorting works % acyclic. In the example we show how topological sorting works
% for a linear graph: % for a linear graph:
% %
% ?- top_sort([1-[2], 2-[3], 3-[]], L). % ```
% L = [1, 2, 3] % ?- top_sort([1-[2], 2-[3], 3-[]], L).
% L = [1, 2, 3]
% ```
top_sort(Graph, Sorted) :- top_sort(Graph, Sorted) :-
vertices_and_zeros(Graph, Vertices, Counts0), vertices_and_zeros(Graph, Vertices, Counts0),
@@ -412,8 +438,8 @@ top_sort(Graph, Sorted) :-
%% top_sort(+Graph, -Sorted, ?Tail) is semidet. %% top_sort(+Graph, -Sorted, ?Tail) is semidet.
% %
% The predicate top\_sort/3 is a difference list version of % The predicate `top_sort/3` is a difference list version of
% top\_sort/2. % `top_sort/2`.
top_sort(Graph, Sorted0, Sorted) :- top_sort(Graph, Sorted0, Sorted) :-
vertices_and_zeros(Graph, Vertices, Counts0), vertices_and_zeros(Graph, Vertices, Counts0),
@@ -496,13 +522,15 @@ decr_list(Neibs, [_|Vertices], [N|Counts1], [N|Counts2], Zi, Zo) :-
% Neigbours is a sorted list of the neighbours of Vertex in Graph. % Neigbours is a sorted list of the neighbours of Vertex in Graph.
% Example: % Example:
% %
% ?- neighbours(4,[1-[3,5],2-[4],3-[], % ```
% 4-[1,2,7,5],5-[],6-[],7-[],8-[]], NL). % ?- neighbours(4,[1-[3,5],2-[4],3-[],
% NL = [1,2,7,5] % 4-[1,2,7,5],5-[],6-[],7-[],8-[]], NL).
% NL = [1,2,7,5]
% ```
%% neighbors(+Vertex, +Graph, -Neigbours) is det. %% neighbors(+Vertex, +Graph, -Neigbours) is det.
% %
% Same as neighbours/3 % Same as `neighbours/3`.
neighbors(Vertex, Graph, Neig) :- neighbors(Vertex, Graph, Neig) :-
neighbours(Vertex, Graph, Neig). neighbours(Vertex, Graph, Neig).
@@ -523,13 +551,15 @@ neighbours(V,[_|G],Neig) :-
% %
% Can be used to order a not-connected graph as follows: % Can be used to order a not-connected graph as follows:
% %
% top_sort_unconnected(Graph, Vertices) :- % ```
% ( top_sort(Graph, Vertices) % top_sort_unconnected(Graph, Vertices) :-
% -> true % ( top_sort(Graph, Vertices)
% ; connect_ugraph(Graph, Start, Connected), % -> true
% top_sort(Connected, Ordered0), % ; connect_ugraph(Graph, Start, Connected),
% Ordered0 = [Start|Vertices] % top_sort(Connected, Ordered0),
% ). % Ordered0 = [Start|Vertices]
% ).
% ```
connect_ugraph([], 0, []) :- !. connect_ugraph([], 0, []) :- !.
connect_ugraph(Graph, Start, [Start-Vertices|Graph]) :- connect_ugraph(Graph, Start, [Start-Vertices|Graph]) :-
@@ -542,7 +572,7 @@ connect_ugraph(Graph, Start, [Start-Vertices|Graph]) :-
% Unify Before to a term that comes before Term in the standard % Unify Before to a term that comes before Term in the standard
% order of terms. % order of terms.
% %
% Throws instantiation_error if Term is unbound. % Throws `instantiation_error` if Term is unbound.
before(X, _) :- before(X, _) :-
var(X), var(X),
@@ -561,12 +591,13 @@ before(_, 0).
% _not_ connected in UGraphIn and all edges from UGraphIn removed. % _not_ connected in UGraphIn and all edges from UGraphIn removed.
% Example: % Example:
% %
% ?- complement([1-[3,5],2-[4],3-[], % ```
% 4-[1,2,7,5],5-[],6-[],7-[],8-[]], NL). % ?- complement([1-[3,5],2-[4],3-[],
% NL = [1-[2,4,6,7,8],2-[1,3,5,6,7,8],3-[1,2,4,5,6,7,8], % 4-[1,2,7,5],5-[],6-[],7-[],8-[]], NL).
% 4-[3,5,6,8],5-[1,2,3,4,6,7,8],6-[1,2,3,4,5,7,8], % NL = [1-[2,4,6,7,8],2-[1,3,5,6,7,8],3-[1,2,4,5,6,7,8],
% 7-[1,2,3,4,5,6,8],8-[1,2,3,4,5,6,7]] % 4-[3,5,6,8],5-[1,2,3,4,6,7,8],6-[1,2,3,4,5,7,8],
% % 7-[1,2,3,4,5,6,8],8-[1,2,3,4,5,6,7]]
% ```
% TODO: Simple two-step algorithm. You could be smarter, I suppose. % TODO: Simple two-step algorithm. You could be smarter, I suppose.
@@ -586,8 +617,10 @@ complement([V-Ns|G], Vs, [V-INs|NG]) :-
% True when Vertices is an ordered set of vertices reachable in % True when Vertices is an ordered set of vertices reachable in
% UGraph, including Vertex. Example: % UGraph, including Vertex. Example:
% %
% ?- reachable(1,[1-[3,5],2-[4],3-[],4-[5],5-[]],V). % ```
% V = [1, 3, 5] % ?- reachable(1,[1-[3,5],2-[4],3-[],4-[5],5-[]],V).
% V = [1, 3, 5]
% ```
reachable(N, G, Rs) :- reachable(N, G, Rs) :-
reachable([N], G, [N], Rs). reachable([N], G, [N], Rs).

View File

@@ -9,20 +9,22 @@ This library provides reasoning and working with [UUID](https://en.wikipedia.org
(only version 4 right now). (only version 4 right now).
There are three predicates: There are three predicates:
* uuidv4/1, to generate a new UUIDv4
* uuidv4\_string/1, to generate a new UUIDv4 in string hex representation * `uuidv4/1`, to generate a new UUIDv4
* uuid\_string/2, to converte between UUID list of bytes and UUID hex representation * `uuidv4_string/1`, to generate a new UUIDv4 in string hex representation
* `uuid_string/2`, to converte between UUID list of bytes and UUID hex representation
Examples: Examples:
?- uuidv4(X). ```
X = [42,147,248,242,117,196,79,2,129,159|...]. ?- uuidv4(X).
?- uuidv4_string(X). X = [42,147,248,242,117,196,79,2,129,159|...].
X = "428499fc-76e3-4240- ...". ?- uuidv4_string(X).
?- uuidv4(X), uuid_string(X, S). X = "428499fc-76e3-4240- ...".
X = [173,12,244,152,139,118,64,139,137,4|...], S = "ad0cf498-8b76-408b- ...". ?- uuidv4(X), uuid_string(X, S).
?- uuid_string(X, "61ae692e-eaf6-4199-8dd3-9f01db70a20b"). X = [173,12,244,152,139,118,64,139,137,4|...], S = "ad0cf498-8b76-408b- ...".
X = [97,174,105,46,234,246,65,153,141,211|...]. ?- uuid_string(X, "61ae692e-eaf6-4199-8dd3-9f01db70a20b").
X = [97,174,105,46,234,246,65,153,141,211|...].
*/ */
:- module(uuid, [ :- module(uuid, [
@@ -64,7 +66,7 @@ uuidv4(Uuid) :-
%% uuidv4_string(-UuidString). %% uuidv4_string(-UuidString).
% %
% Generates a new UUID v4 (random). It unifies with a string representation of the UUID. % Generates a new UUID v4 (random). It unifies with a string representation of the UUID.
% It is equivalent of calling uuidv4/1 followed by uuid\_string/2. % It is equivalent of calling `uuidv4/1` followed by `uuid_string/2`.
uuidv4_string(String) :- uuidv4(Uuid), uuid_string(Uuid, String). uuidv4_string(String) :- uuidv4(Uuid), uuid_string(Uuid, String).
%% uuid_string(?UuidBytes, ?UuidString). %% uuid_string(?UuidBytes, ?UuidString).