1% * -*- Mode: Prolog -*- */
15:- module(emulate_builtins, 16 [ 17 ensure_atom/2, 18 ensure_string/2, 19 ensure_atoms/2, 20 lcase/2, 21 regex/2, 22 regex/3, 23 str_starts/2, 24 str_ends/2, 25 str_before/3, 26 str_after/3, 27 28 str_replace/4, 29 concat/3, 30 concat/4, 31 32 agg_max/2, 33 count/2, 34 group_concat/3, 35 aggregate_group/4, 36 37 iri_prefix_curie/3, 38 iri_prefix/2, 39 iri_curie/2, 40 curie_prefix/2, 41 42 optional/1, 43 rdf_path/3, 44 rdf_path/4, 45 46 if/4, 47 48 bind/2, 49 seval/2, 50 eval_to_atom/2 51 ]). 52 53:- use_module(library(semweb/rdf11)). 54:- use_module(library(pcre)). 55 56 57/* 58https://www.w3.org/TR/sparql11-query/#expressions 59 60*/ 61 62 63/* ---------- 64 https://www.w3.org/TR/sparql11-query/#func-strings 65 66 all string functions take as arguments either: 67 68 - prolog string 69 - prolog atom (converted to strong) 70 - prolog rdf11 literal: either String@Lang or String^^xsd:string 71 72*/
78lcase(S,V) :-
79 ensure_atom(S,S1),
80 downcase_atom(S1,V1),
81 ensure_string(V1,V).
83ucase(S,V) :- 84 ensure_atom(S,S1), 85 upcase_atom(S1,V1), 86 ensure_string(V1,V). 87 88% 17.4.2.5 str 89str(X,V) :- 90 ensure_atom(X,A), 91 atom_string(A,V). 92 93% 17.4.2.6 lang 94lang(_^^L,L). 95 96%17.4.2.7 datatype 97datatype(_^^D, D) :- !. 98datatype(_ @ _, xsd:string) :- !. 99datatype(_, xsd:string) :- !. 100 101 102% 17.4.2.8 iri 103iri(X,V) :- 104 ensure_atom(X,A), 105 atom_string(A,V). 106uri(X,V) :- iri(X,V).
corresponds to re_match/2 in SPARQL
117regex(S,P) :- 118 regex(S,P,""). 119 120regex(S,P,Flag) :- 121 eval_to_string(S,S1), 122 eval_to_string(P,P1), 123 eval_to_atom(Flag,Flag1), 124 re_match(P1/Flag1, S1).
131eval_to_atom(X,A) :- 132 seval(X,Y), 133 ensure_atom(Y,A). 134 135eval_to_string(X,A) :- 136 seval(X,Y), 137 ensure_string(Y,A).
144str_starts(S,Sub) :-
145 ensure_atom(S,S1),
146 ensure_atom(Sub,Sub1),
147 atom_concat(Sub1,_,S1).
153str_ends(S,Sub) :-
154 ensure_atom(S,S1),
155 ensure_atom(Sub,Sub1),
156 atom_concat(_,Sub1,S1).
162str_before(S,Sep,Sub) :-
163 ensure_atom(S,S1),
164 ensure_atom(Sep,Sep1),
165 atomic_list_concat([Sub1|_],Sep1,S1),
166 ( var(Sub)
167 -> atom_string(Sub1,Sub)
168 ; ensure_atom(Sub,Sub1)).
174str_after(S,Sep,Sub) :-
175 ensure_atom(S,S1),
176 ensure_atom(Sep,Sep1),
177 atomic_list_concat([_|Toks],Sep1,S1),
178 atomic_list_concat(Toks,Sep1,Sub1),
179 ensure_atom(Sub,Sub1).
185str_replace(S,In,Out,NewS) :-
186 ensure_atom(S,S1),
187 ensure_atom(In,In1),
188 ensure_atom(Out,Out1),
189 atomic_list_concat(Toks,In1,S1),
190 atomic_list_concat(Toks,Out1,NewS1),
191 ensure_string(NewS1,NewS).
199concat(S1,S2,S) :-
200 concatl([S1,S2],S).
206concat(S1,S2,S3,S) :- 207 concatl([S1,S2,S3],S). 208 209 210concatl(L,S) :- 211 maplist(ensure_atom,L,LA), 212 concat_atom(LA,SA), 213 ensure_string(SA,S). 214 215% for compat
221count(L,N) :- length(L,N).
227agg_max(L,N) :- aggregate(max(X),member(X,L),N).
235group_concat(L, Sep, V) :- 236 maplist(ensure_atom,L,L1), 237 ensure_atom(Sep,Sep1), 238 atomic_list_concat(L1,Sep1,V1), 239 ensure_string(V1,V). 240 241:- module_transparent(aggregate_group/4).
equivalent to GROUP BY queries in SPARQL
maps to aggregate/3 in prolog
250aggregate_group(AggExpr, _GroupBys, Goal, Val) :- 251 aggregate(AggExpr, Goal, Val). 252 253 254 255/* 256 257%! aggregate_group(?AggExpr, ?[Witness], ?Goal, ?RWitness-RVal) is nondet. 258aggregate_group(AggExpr, [Witness], Goal, RWitness-RVal) :- 259 AggExpr =.. [Pred, Val], 260 GTerm =.. [Pred, Witness, Val], 261 RTerm =.. [Pred, RWitness, RVal], 262 aggregate(GTerm,Goal,RTerm). 263*/ 264 265%:- rdf_meta rdf_path(r,r,r). 266%:- rdf_meta rdf_path(r,r,r,g).
See https://www.w3.org/TR/sparql11-query/#propertypaths
Path = Pred OR \Path OR P|Q OR P\Q OR zeroOrMore(Path) OR oneOrMore(Path) OR inverseOf(Path)
279rdf_path(A,P,B) :- rdf_path(A,P,B,_). 280 281rdf_path(A,(\P),B,G) :- rdf_path(B,P,A,G). 282rdf_path(A,inverseOf(P),B,G) :- rdf_path(B,P,A,G). 283rdf_path(A,(P|Q),B,G) :- (rdf_path(A,P,B,G) ;rdf_path(A,Q,B,G)). 284rdf_path(A,(P/Q),B,G) :- rdf_path(A,P,Z,G), rdf_path(Z,Q,B,G). 285 286rdf_path(A,zeroOrMore(_),A,_). 287rdf_path(A,zeroOrMore(P),B,G) :- rdf_path(A,oneOrMore(P),B,G). 288 289rdf_path(A,oneOrMore(P),B,G) :- rdf_path(A,P,B,G). 290rdf_path(A,oneOrMore(P),B,G) :- rdfx(A,P,Z,G),rdf_path(Z,oneOrMore(P),B,G). 291 292rdf_path(A,P,B,G) :- rdfx(A,P,B,G). 293 294% true if there is a triple A-P-B in G 295% where P is either a URI or an atom representation of a CURIE 296rdfx(A,P,B,G) :- 297 ground(P), 298 rdf_global_id(P,Px), 299 atomic(Px), 300 rdf(A,Px,B,G). 301 302:- rdf_meta iri_prefix_curie(r,o,o). 303iri_prefix_curie(IRI, Prefix, CURIE) :- 304 ground(IRI), 305 !, 306 rdf_global_id(Prefix:Local, IRI), 307 concat_atom([Prefix,Local],':',CURIE). 308iri_prefix_curie(IRI, Prefix, CURIE) :- 309 ground(CURIE), 310 !, 311 concat_atom([Prefix,Local],':',CURIE), 312 rdf_global_id(Prefix:Local, IRI). 313iri_curie(IRI, CURIE) :- 314 iri_prefix_curie(IRI, _, CURIE). 315iri_prefix(IRI, Prefix) :- 316 iri_prefix_curie(IRI, Prefix, _). 317curie_prefix(CURIE, Prefix) :- 318 str_before(CURIE,":",Prefix).
equivalent to OPTIONAL in SPARQL
329:- module_transparent(optional/1). 330optional(G) :- ,!. 331optional(_). 332 333entailed(G,AssertedG) :- 334 entailed(G,AssertedG,_,[]). 335entailed(G,AssertedG,Goals,_Opts) :- 336 G =.. [P|Args], 337 map_args_to_equiv(Args,Args2,Goals), 338 % TODO: query optimization 339 all_succeed(Goals), 340 AssertedG =.. [P|Args2], 341 . 342 343map_args_to_equiv([],[],[]). 344map_args_to_equiv([A|L],[A2|L],[G|GL]) :- 345 G=owl_equivalent_class(A,A2), 346 map_args_to_equiv(L,L,GL). 347 348all_succeed([]). 349all_succeed([G|L]) :- 350 , 351 all_succeed(L). 352 353 354 355 356 357%! ensure_atom(?Str:strlike, ?Atom:atom) is det 358% 359% convert a string, literal, or any strlike entity to an atom 360ensure_atom(S@_, A) :- !, atom_string(A,S). 361 362ensure_atom(S^^_, A) :- !, string(S), atom_string(A,S). 363 364ensure_atom(A, A) :- atom(A), !. 365 366ensure_atom(S, A) :- string(S), !, atom_string(A,S).
371ensure_string(S,S) :- string(S),!. 372 373ensure_string(A,S) :- atom(A), !, atom_string(A,S). 374 375ensure_string(A,_) :- throw(ensure_string(A)).
382ensure_atoms(L, L2) :- maplist([A,B]>>ensure_atom(A,B),L,L2). 383 384 385ensure_number(N, N) :- number(N),!. 386ensure_number(S^^_, N) :- !, atom_string(A,S), atom_number(A,N). % todo: fail if incorrect datatype? 387ensure_number(literal(type(_,S)), N) :- !, atom_string(A,S), atom_number(A,N). % todo: fail if incorrect datatype? 388ensure_number(S, N) :- string(S), !, atom_string(A,S), atom_number(A,N). 389ensure_number(A, N) :- atom(A), !, atom_number(A,N). 390 391% 17.4.1.1 bound 392bound(Expr) :- nonvar(Expr). 393 394% 17.4.1.2 IF
400if(E1, E2, E3, R) :- 401 ( 402 -> bind(E2, R) 403 ; bind(E3, R)). 404 405% 17.4.1.3 COALESCE 406coalesce([H|_],R) :- 407 bind(H, R), 408 nonvar(R), 409 !. 410coalesce([_|T],R) :- 411 coalesce(T,R).
414exists(E) :- \+ \+ . 415 416% 17.4.1.8 sameTerm : use == 417 418% 17.4.1.9 IN : use member/2 419 420% 17.4.2.1 isIRI : use rdf_is_iri
433bind(Expr,Result) :-
434 seval(Expr, Result).
this is the same as bind/2 with args reversed.
442:- module_transparent(seval/2). 443 444seval(L,L2) :- 445 is_list(L), 446 !, 447 maplist(seval,L,L2). 448 449 450seval(V, V) :- var(V),!. 451 452seval(T, T) :- T = _@_, !. 453 454seval(T, T) :- T = _^^_, !. 455 456seval(T, T) :- T = literal(_), !. 457 458seval(T, T) :- is_aggregate_goal(T),!. 459 460seval(Term, Ret) :- 461 compound(Term), 462 !, 463 Term =.. [P|Args], 464 maplist(seval,Args,EArgs), 465 ( ArithTerm =.. [P|EArgs], 466 current_arithmetic_function(ArithTerm), 467 maplist(ensure_number,EArgs,NArgs), 468 ArithTerm2 =.. [P|NArgs], 469 arithmetic_expression_value(ArithTerm2,Ret) 470 -> true 471 ; append(EArgs,[Ret],GoalArgs), 472 Goal =.. [P|GoalArgs], 473 ). 474seval(X,X). 475 476is_aggregate_goal(aggregate_group(_,_,_,_)). 477is_aggregate_goal(aggregate(_,_,_))
emulate builtins
This module allows you to write programs that can be executed on a triplestore or directly on the in-memory SWI-Prolog rdf database.
Sparqlprog defines predicates such as rdf_path/3 and str_starts/2. These are usually compiled down to SPARQL queries. This module provides prolog implementations for these predicates using predicates such as rdf/3
Many of the predicates here take an argument strlike - this can be either an atom or a string.
*/