%Copyright 2001-2002 Bijan Parsia All rights reserved %November 28, 2001 %February 20, 2002 %Not currently for redistribution :-use_module(library(url)). :-use_module(library(rdf_db)). %The intent of this is to support a CWM clone that is % 1) easy to understand (the code that is) % 2) easy to modify (even for non-TBL people) % 3) fast (especially with complex queries) % 4) transparent (e.g., you can get at the underlying objects) % 5) interactive (at least potentially) %%%My god, was that *really* my intent?! %Some immediate tasks not in the "missing" lists below: % X) An n3 REPL. (Basically there) % X) An n3 file reader (end of file bug) % 3) n3_retract/? % Hmm. Do I *want* to be able to retract N3 *statments*? % Might be handy. % 4) n3_assert/1 (take a string?) % 5) N3 compatible namespace handling. ( % This is trickier than it sounds. rdf_db doesn't % let you overwrite prior prefix declarations, % whereas n3 requires it. % OTOH, it stores everything expanded... % ------ % Ok, I just hack into rdf_db directly. % XXX Current problem is 1) default prefix and 2) not full uris <#foo>. % 6) this file needs refactoring into separate modules. %Things I don't care particularly about (yet): % 1) pretty printing N3 code % 2) coverting to/from N3, RDF/XML, N-Triples, etc. % not that it should be hard to support some o' that % and some o' that might be useful for various testing purposes %Cool things I'd like to see/do: % 1) N3 support in PCEmacs. % 2) The things I don't care particularly about % 3) A multipane/mode REPL/editor/query thing. % Lot's of wild ideas here. Be nice to % be able to switch back and forth between % entering N3, querying it, exploring it, % and using prolog. % It'd be *super cool* to have a dynamically % updated view onto the triple store, either % in a triple list form, or graphical % 4) In the latest SWI package, there's a cool feature % in PEmacs, the "Prolog navigator". It let's you view % Prolog files in a Explorer like outline window, including % the contents with basic info about the definitions (e.g., % that somthing's a DCG, a normal pred, etc. etc.). %Pitfalls of the current implementation % 1) One must be careful not to accidentally merge % two documents by reading them into the same % db, or, maybe worse, reading one into a sub-context % of another. % 2) That may be a feature, not a bug :) %consult_n3('C:\\My Documents\\Writing\\Prolog3\\test.n3', user). %['C:\\My Documents\\Writing\\cwmclone\\cwmclone.P']. %%%%%%%%%%%%REPL and reading%%%%%%%%%% %consult_n3(path_to_file, user). %best bet %Be sure to observe current sytnax restrictions, most %annoyingly about default prefixes (no :xs!) %Need to check out library(readtuils). Maybe. consult_n3(File, Db) :- rdf_db(Old_db, Db), see(File), read_n3_from_current_file, seen, rdf_db(_, Old_db). read_n3_from_current_file :- repeat, read_n3_form(Tokens), (Tokens = [] -> (at_end_of_stream, !, write_ln(alldone)) ; (n3_form(Tokens, []), fail)). %peek_char(End), %write_ln(end), %End = -1. n3_test_repl :- prompt(Old, 'n3:- '), repeat, read_n3_form(X), (X=['@', 'stop', '.'],! ; write_ln(X), fail), prompt(_, Old). n32_repl :- prompt(Old, 'n32:- '), repeat, write_ln(startingread), read_n3_form(Tokens), write('done read: '), write_ln(Tokens), Tokens = ['@', 'stop', '.'], !, write_ln('All done.'). n3_repl :- prompt(Old,'n3:- '), repeat, %write_ln(startingread), read_n3_form(Tokens), write('done read: '), write_ln(Tokens), (Tokens = ['@', 'stop', '.'], !; %Tokens = ['@', 'read', '.'], write_ln(here),!; %write_ln(beforetheform), n3_form(Tokens,[]), % -> write_ln(yay); write_ln(boo), %write_ln(pasttheform), peek_char(End), fail %End=end_of_file, write_ln(psotend),! ), prompt(_, Old). n3_repl(end_of_file). n3_repl(_) :- n3_repl. %%%%%%%%%%%%%% TOKENIZER %%%%%%%%%%%%%% %Still missing: % Comments (# to end of line) % Partial support, but still not quite right. % Most string literal forms. % Handles ', and ", but not """ % Quote escaping not handled. % ???? %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %Somewhat stolen from O'Keefe. % Oooooh man, I suck. Order dependancies. Cuts. %Hangovers. Weird stuff. Oh well. n3_punc(C) :- member(C, "().#@',;{}[]\"\\="). n3_end(C) :- C is 10. :-dynamic n3_nesting/1. incr_n3_nesting :- n3_nesting(Nest_level), New_nest_level is Nest_level + 1, retract(n3_nesting(Nest_level)), asserta(n3_nesting(New_nest_level)). decr_n3_nesting :- n3_nesting(Nest_level), New_nest_level is Nest_level - 1, retract(n3_nesting(Nest_level)), asserta(n3_nesting(New_nest_level)). read_n3_form(Tokens) :- get0(C), asserta(n3_nesting(0)), read_n3_form(C, Tokens),!, retract(n3_nesting(0)). read_n3_form(-1,[]). read_n3_form(C, Tokens) :- code_type(C, space),!, %skip spaces get0(C1), read_n3_form(C1, Tokens). read_n3_form(60, ['<', Uriref, '>'|Tokens]) :- read_uriref(Uriref), get0(C), read_n3_form(C, Tokens). %read_n3_form(46, ['.']) :- % peek_code(C), n3_end(C),!. %Maybe only for prompt driven. %For file driven, EOF. %read_n3_form(46, ['.'|Tokens]) :- % read_n3_form(Tokens). read_n3_form(C, Tokens) :- n3_punc(C), handle_n3_punc(C, Tokens). read_n3_form(C, [Token|Tokens]) :- read_symbol(C, Chars, C1), atom_codes(Token, Chars),%db(Token), read_n3_form(C1, Tokens). read_symbol(C, [C|Chars], Left) :- (code_type(C, csym); member(C,"-:")),!, get0(C1), read_symbol(C1, Chars, Left). read_symbol(C, [], C) :- (code_type(C, space); member(C, "=#;,]}).")),!. %Should '=' be in there? handle_n3_punc(46, ['.'|Tokens]) :- n3_nesting(0) -> Tokens = []; get0(C), read_n3_form(C, Tokens). handle_n3_punc(35, Tokens) :- % '#' is comment til end of line. read_n3_string(10,_), read_n3_form(10,Tokens). %Lil cheat. handle_n3_punc(C, Tokens) :- code_type(C, quote),!, handle_n3_quote(C, Tokens). handle_n3_punc(123, ['{'|Tokens]) :- incr_n3_nesting, get0(C), read_n3_form(C, Tokens). handle_n3_punc(125, ['}'| Tokens]) :- decr_n3_nesting, get0(C), read_n3_form(C,Tokens). handle_n3_punc(C, [C_symbol|Tokens]) :- char_code(C_symbol, C),!, get0(C1), read_n3_form(C1, Tokens). handle_n3_quote(96,['`',Tokens]) :- get0(C), read_n3_form(C, Tokens). handle_n3_quote(C,[literal(String)|Tokens]):- read_n3_string(C,Chars), atom_codes(String, Chars), %write_ln(String), %string_to_list(String,Chars), get0(C1), read_n3_form(C1, Tokens). %Return the list of chars *without* the surrounding ',", or """s %Escaping of Quotes not done yet. read_n3_string(End, Chars) :- get0(C), read_rest_of_string(C, Chars, End). read_rest_of_string(C, [], C):-!. read_rest_of_string(C, [C|Chars], End):- get0(C1),%db(C1), read_rest_of_string(C1,Chars, End). %If performance problems, may want to check uriness *here* %Need to expand URI frags, maybe here? read_uriref(Uriref) :- get0(C), %don't skip spaces, let the uri checker sort it out read_uri(C, Urichars), atom_codes(Uriref, Urichars). read_uri(62, []). %> closes the uri ref. %read_uri(35, Token) :- % peek_char(C), % C = 62. %signal syntax error! % current_n3_document_base_uri(Uri), % (atom_concat(Stripped_uri, '#', Uri) -> % n3_prefix('default_', Stripped_uri); % n3_prefix('default_', Uri)). read_uri(C, [C|Chars]) :- %char_code(Cc, C),write_ln(Cc), get0(C1), read_uri(C1, Chars). %%%%%%%%%%%%%% Parser/DCG Grammar %%%%% %This handles one complete, top level %N3 statement. It's recursive in the sense %that nested statements are correctly handled %(Though not *as* statements, per se.) No %nested directives though. % %Still missing: % Lists % Some special recognition of variablesXXXXALL HANDLED % 'this', 'a', are handled, '=' is not % prefix checking % Most error and sanity checking % Error handling/reports. % Some obscure to me or obsolete bits. % Some odd stuff like predicate literals. n3_form --> directive.%, {write_ln(directive)}. %ugh, backtrack city :) n3_form --> {rdf_db(Context)},statement(Context). %directive --> % ['@', 'stop', '.'],!, {write_ln('Stopping.')}. directive --> ['@','prefix'], prefix(Prefix), uriref(Uri), ['.'], {n3_prefix(Prefix, Uri)}. n3_prefix(Prefix, Uri) :- Prefix = '' -> n3_prefix2(default_,Uri) ; n3_prefix2(Prefix, Uri). n3_prefix2(Prefix, Uri) :- rdf_db:ns(Prefix, Different_uri) -> retract(rdf_db:ns(Prefix,Different_uri)), assert(rdf_db:ns(Prefix, Uri)) ; assert(rdf_db:ns(Prefix, Uri)). %n3_prefix(Prefix,Uri) :- % assert(rdf_db:ns(Prefix, Uri). prefix(Prefix) --> [Token], {atom_concat(Prefix, ':', Token)}. uriref(Uri) --> ['<'], [Possible_uri], ['>'], {normalize_uri(Possible_uri,Uri)}. normalize_uri('#', Uri) :- Uri='document#',!. normalize_uri(Possible_uri, Uri) :- Uri = Possible_uri. %parse_url(Possible_uri, Uri). statement(Context) --> clause(Context),!, ['.']. clause(Context) --> subject(Context, Subject_uri), predicate_phrase(Context, Subject_uri). %predicate_phrase may be empty. predicate_phrase(Context, Subject_uri) --> verb(Context, Verb_uri), objects(Context, Subject_uri, Verb_uri), end_predicate_phrase(Context, Subject_uri, Verb_uri). predicate_phrase(Context, Subject_uri) --> []. %Throw it away. The enclosed triple is already asserted. end_predicate_phrase(Context, Subject_uri, Verb_uri) --> [;], predicate_phrase(Context, Subject_uri). end_predicate_phrase(Context, Subject_uri, Verb_uri) --> []. anonymous_phrase(Context, Uri) --> {rdf_gen_id(anon_,Uri)}, ['['], predicate_phrase(Context, Uri), [']']. %this doens't allow trailing ';'s %which I think is bad (allowing it), and the blindfold %grammar doesn't seem to allow anyway :). quoted_statements(Uri) --> {rdf_gen_id(Uri)}, %Uri is also the context of the nestd statements. %Alas, it's not *actaully* a URI per se :) ['{'], statement_list(Uri), ['}']. statement_list(Context) --> clause(Context), statement_list_rest(Context). statement_list_rest(Context) --> ['.'], statement_list(Context). statement_list_rest(Context) --> ['.']; []. subject(Context, Uri) --> node(Context, Uri). subject(Context, Uri) --> literal_node(Uri). %Ooo. feels broken! verb(Context, Uri) --> node(Context, Uri). objects(Context, Subject, Verb) --> object_node(Context, Subject, Verb), rest_of_objects(Context, Subject, Verb). rest_of_objects(Context, Subject, Verb) --> [','], object_node(Context, Subject, Verb), rest_of_objects(Context, Subject, Verb). rest_of_objects(Context, Subject, Verb) --> []. node(Context, Uri) --> a_name(Uri); quoted_statements(Uri); anonymous_phrase(Context, Uri); daml_list(Context, Uri); ([=], {Uri = 'http://www.daml.org/2001/03/daml+oil#equivaent'}); [this], {Uri = this}.%Context}. /* [ a daml:List; daml:first "http://example.org/#blargh"; daml:rest [daml:first "#"; daml:rest daml:nil ] ] */ daml_list(Context, Uri) --> ['('], daml_list_body(Context, Uri). %, [')']. %daml_list_body(Context, Id) --> % [], {rdf_assert(Id, daml:rest, daml:nil, Context)}. daml_list_body(Context, Id) --> [')'], {rdf_gen_id(anon_list_, Id), rdf_assert(Id, daml:rest, daml:nil, Context)}. daml_list_body(Context, Id) --> {rdf_gen_id(anon_list_, Id)}, (literal_node(First) ; node(Context, First)), %; daml_list_end(First)), {rdf_assert(Id, rdf:type, daml:'List', Context), rdf_assert(Id, daml:first, First, Context)}, daml_list_body(Context, New_id), {rdf_assert(Id, daml:rest, New_id, Context)}. object_node(Context, Subject, Verb) --> literal_node(Object), {rdf_assert(Subject, Verb, Object, Context), dbassert(Subject, Verb, Object, Context)}. object_node(Context, Subject, Verb) --> node(Context, Object), {rdf_assert(Subject, Verb, Object, Context), dbassert(Subject, Verb, Object, Context)}. literal_node(literal(Strlit)) --> [literal(Strlit)].%, {string(Strlit)}. a_name(Uri) --> uriref(Uri). a_name(Name) --> qname(Name). a_name('http://www.w3.org/1999/02/22-rdf-syntax-ns#type') --> [a]. %a_name --> ['=']. %qname(Prefix:Name) --> [Symbol], % {atom_concat(Colon_bit, Name, Symbol), % atom_concat(Prefix,':', Colon_bit)}. qname(Name) --> [Qname], {expand_qname(Qname, Name)}. expand_qname(Qname, Name) :- atom_concat(Pre, Possible_name, Qname), atom_concat(Prefix,':', Pre), expand_qname(Prefix, Possible_name, Name). expand_qname('',Name, default_:Name). expand_qname(Prefix, Name, Prefix:Name). %expr --> [this]. %expr --> exvar. %expr --> uvar. %Helper predicates %This needs to be beefed up, obviously. Default Namespaces need to be %handled properly. %check_qname(Prefix, Name, Uri) :- % rdf_db:ns(Prefix,Ns), % rdf_db:globalise(Ns:Name, Uri). dbassert(S, V, O, C) :- write('S: '),write(S), write(' V: '),write(V), write(' O: '),write(O), write(' C: '),write_ln(C). %%%%%%%%%%%%% Inference Engine %%%% %Not much too it, yet. %I'd like a CWM clone, just for the heck of it. %No builtins yet. %I don't handle scoped log:forAlls well (er..at all?) % From the book % PROLOG PROGRAMMING IN DEPTH % by Michael A. Covington, Donald Nute, and Andre Vellino % (Prentice Hall, 1997). % Copyright 1997 Prentice-Hall, Inc. %It's for 'educational use only'. Is this educational use? %I've really really hacked the hell out of it. %was "forward_chainer", "apply_rules" is from llyn.py. %Apply_rules should *only* apply to the context where the rules are found! %If you try to use it to filter you *will* get an infinite loop. %IOW, apply_rules(user). is *IT*. apply_rules(Results) :- findall(X, satisfied(X, Id, Results), Applicable_rules), write_ln(Applicable_rules), %resolve_set(Applicable_rules, Nr), %n3implies(Nr, Id, Results), (Applicable_rules = [], !, fail; do_current_round(Applicable_rules, Results), %This is generated rules may be applied next round. %Alas, this recompiles *all* the rules. I don't know how hard a hit that will be. compile_rules(user), !, apply_rules(Results)). %filter(user, test). then rdf(X,Y,Z, test). to see results. filter(From, To) :- findall(X, satisfied(X, Id, To), Applicable_rules), write_ln(Applicable_rules), (Applicable_rules = [], !, fail; do_current_round(Applicable_rules, To)). do_current_round([], Results). do_current_round([Nr | Applicable_rules], Results) :- %write('About to apply rule: '), write(Nr), (n3implies(Nr, _, Results); true), %write_ln('. Applied it.'), do_current_round(Applicable_rules, Results). satisfied(X, Id, R) :- clause(n3implies(X, Id, R),Body), satisfied_conditions(Body). satisfied_conditions((logimplies,_)) :- !. satisfied_conditions((First,Rest)) :- First, %write_ln(First), satisfied_conditions(Rest). resolve_set([ID|_], ID) :-!. logimplies. :-dynamic n3implies/2. set_up_vars([],[]). set_up_vars([N3id|Id_list], [N3id/Var|Var_list]) :- hash_term(N3id, Id_hash), atom_concat('Var_', Id_hash, Var_atom), atom_to_term(Var_atom, Var, _), set_up_vars(Id_list, Var_list). get_vars_for(Context, Vars) :- setof(Var, rdf(this, log:forAll, Var, Context), Vars); %That "log" is unsafe. Vars = []. get_e_vars_for(Context, Vars) :- findall(S,(rdf(S, _, _, Context),\+S=literal(_),atom_prefix(S,anon_)),Ss), findall(P,(rdf(_, P, _, Context),\+P=literal(_),atom_prefix(P,anon_)),Ps), findall(O,(rdf(_, _, O, Context),\+O=literal(_),atom_prefix(O,anon_)),Os), union(Ss, Ps, Temp), union(Temp, Os, Temp2), list_to_set(Temp2, Vars). %HORK!!! get_all_e_vars(Vars) :- findall(S,(rdf(S, _, _, _),\+S=literal(_),atom_prefix(S,anon_)),Ss), findall(P,(rdf(_, P, _, _),\+P=literal(_),atom_prefix(P,anon_)),Ps), findall(O,(rdf(_, _, O, _),\+O=literal(_),atom_prefix(O,anon_)),Os), union(Ss, Ps, Temp), union(Temp, Os, Temp2), list_to_set(Temp2, Vars). write_context(Context) :- rdf(X, Y, Z, Context),!, write_ln([X, Y, Z]), write_context(Context). %compile_rules(In_context) :- % forall(rdf(A, log:implies, C, In_context), compile_n3_rule(In_context, A, C)). clean_rules :- retractall(n3implies(_,_,_)), write_ln(cleaned). kill_old_rule(In_context, Antecedent, Consequent, Nr) :- Head = n3implies(Nr, id(In_context, Antecedent, Consequent),_), clause(Head, Body), retract(Head :- Body) ; n3_rule_nr(Nr). %Bad bad, defining context gets hard coded in. %Hmm. *is* this bad? It makes it hard to export compiled rules. %Or to apply them to different contexts.http://www.unc.edu/~bparsia/sw/cwmclone/ %E.g., it'd be nice to be able to: % filter(user, test). % apply_rules(test). %and have the rules "apply" to the new context. Right now, they won't. %Hmm. How bad *is* this? I'm unclear. compile_n3_rule(In_context, Antecedent, Consequent) :- rdf(Antecedent, log:implies, Consequent, In_context), kill_old_rule(In_context, Antecedent, Consquent, Nr),!, get_vars_for(In_context, V), set_up_vars(V, V1), setof(Clause, n3_clause(Antecedent, In_context, V1, rdf, Clause), Ante_clauses), setof(Clause, n3_clause(Consequent, Results, V1, rdf, Clause), Con_test_clauses), setof(Clause, n3_clause(Consequent, Results, V1, rdf_assert, Clause), Con_clauses), conjoin_list(Ante_clauses, Ant), conjoin_list(Con_test_clauses, Test), conjoin_list(Con_clauses, Con), Neg_test=..[\+, Test], conjoin_list([Ant, Neg_test, logimplies, Con],Body), %conjoin_list([Ant, logimplies, Neg_test, Con],Body), %n3_rule_nr(Rule_nr), write_ln(X), Rule =..[':-', n3implies(Nr, id(In_context, Antecedent, Consequent), Results), Body], write_ln(Rule), assert(Rule). %Adding proper handling of bNodes, and builtins. %Fixing the negtest. compile_rules(In_context) :- forall(rdf(A, log:implies, C, In_context), compile_n3_rule_ALPHA(In_context, A, C)). compile_n3_rule_ALPHA(In_context, Antecedent, Consequent) :- rdf(Antecedent, log:implies, Consequent, In_context), kill_old_rule(In_context, Antecedent, Consquent, Nr),!, %Need to kill that. get_vars_for(In_context, V), set_up_vars(V, V1), antecedent_clause(Antecedent, In_context, V1, Ant_clause), test_clause(Consequent, Results, V1, Test_clause), consequent_clause(Consequent, Results, V1, Con_clause), conjoin_list([Ant_clause, Test_clause, logimplies, Con_clause],Body), Rule =..[':-', n3implies(Nr, id(In_context, Antecedent, Consequent), Results), Body], write_ln(Rule), assert(Rule). antecedent_clause(Antecedent_ref, In_context, Vars, Clause) :- get_e_vars_for(Antecedent_ref, Evars), set_up_vars(Evars, Bound_evars), append(Vars, Bound_evars, All_vars), setof(C, n3_clause(Antecedent_ref, In_context, All_vars, rdf, C), Raw_ante_clauses), reverse(Raw_ante_clauses, Ante_clauses), % built_in_analysis(Raw_ante_clauses, Ante_clauses), conjoin_list(Ante_clauses, Clause). %Not handling bNodes in antecedent yet. %built_in_analysis(Raw, Clauses) :- % built_in_clauses(Raw, BIs), % . built_in_clauses([], []). built_in_clauses([H|T], Clauses) :- H=..[_,_,P|_], (is_built_in(P) -> append([H], T1, Clauses); Clauses = T1), built_in_clauses(T, T1). test_clause(Consequent_ref, In_context, Vars, Clause) :- get_e_vars_for(Consequent_ref, Evars), set_up_vars(Evars, Bound_evars), append(Vars, Bound_evars, All_vars), setof(C, n3_clause(Consequent_ref, In_context, All_vars, rdf, C), Raw_test_clauses), add_anon_test_clauses(Raw_test_clauses, Bound_evars, Test_clauses), negated_goals(Test_clauses, Clause). add_anon_test_clauses(Raw_test_clauses, Evars, Test_clauses) :- anon_test_clauses(Evars, Clauses), append(Raw_test_clauses, Clauses, Test_clauses). anon_test_clauses([],[]). anon_test_clauses([Name/Var|Evars], [Clause|Clauses]) :- P_term =..[atom_prefix, Var, anon_], Clause =.. [catch, P_term, _, true], anon_test_clauses(Evars, Clauses). consequent_clause(Consequent_ref, In_context, Vars, Clause) :- get_e_vars_for(Consequent_ref, Evars), set_up_vars(Evars, Bound_evars), append(Vars, Bound_evars, All_vars), setof(C, n3_clause(Consequent_ref, In_context, All_vars, rdf_assert, C), Con_clauses), %setof(C, n3_assert_clause(Consequent_ref, In_context, All_vars, n3, C), Con_clauses), Init_clause =.. [set_up_fresh_e_vars, Bound_evars], conjoin_list([Init_clause|Con_clauses], Clause). /* (Bound_evars = [] -> (Init_clause =.. [set_up_fresh_e_vars, Bound_vars, _], conjoin_list([Init_clause|Con_clauses], Clause)) ; conjoin_list(Con_clauses, Clause)).*/ set_up_fresh_e_vars([]).%just walk the list. set_up_fresh_e_vars([Name/Var|Evar_list]):- rdf_gen_id(anon_, Var), set_up_fresh_e_vars(Evar_list). negated_goals(Goal_list, Term) :- conjoin_list(Goal_list, Goals), Term =..[\+,(Goals)]. conjoin_list([H|[]],H). %Why not use concat_atom/3? conjoin_list([H|T], Clause) :- conjoin_list(T, T1), Clause =..[',',H, T1]. n3_rule_nr(Nr) :- predicate_property(n3implies(_,_,_), number_of_clauses(Rule_nr)) -> Nr is Rule_nr + 1,! ; Nr = 1. n3_assert(S, P, O, C, Evars) :- bind_evars(S, V, O, Evars, Bindings), [S1, P1, O1] = Bindings, rdf_assert(S1, P1, O, C). %bind_evars(S, V, O, Evars, Bindings) :- bind_vars(Vars, N3id, Var) :- member(N3id/Var, Vars),!; Var = N3id. n3_assert_clause(Context, Target, Vars, Pred, Clause) :- n3_clause(Context, Target, Vars, Pred, C), Clause =..[assert, C]. n3_clause(Context, Target, Vars, Pred, Clause) :- rdf(S, P, O, Context), bind_vars(Vars, S, S1), bind_vars(Vars, P, P1), bind_vars(Vars, O, O1), make_n3_term(Pred, S1, P1, O1, Target, Clause). make_n3_term(rdf, S, P, O, C, Term) :- (is_built_in(P) -> Term =..[built_in, S, P, O, C]; Term =..[rdf, S, P, O, C]), !. %rather hacky, eh? make_n3_term(Pred, S, P, O, C, Term) :- Term =..[Pred, S, P, O, C]. %n3_clause_with_subs(Context, Vars, Pred, Clause) :- % rdf(S, P, O, Context), % bind_vars(Vars, S, S1), % bind_vars(Vars, P, P1), % bind_vars(Vars, O, O1), % rdf_db(Current_context), % make_n3_term(Pred, S1, P1, O1, Current_context, Clause). %make_n3_term(Module:Pred,S,P,O,C, Term):- %"http://example.org/#blargh" concat_atom([S,P,O,C], ',', Arg_atom), % concat_atom([Module,':',Pred,'(',Arg_atom,')'],Term_atom), % term_to_atom(Term, Term_atom). %{:d string:lessThan "2001"} log:implies {:s a :old}. %{:e a :myEvents. :e :date [string:lessThan "2001"]} log:implies {:e a :old}. %%%%%%%%%%%%Builtins%%%%%%%%% %n3_builtin(S, P, O) :- % call(P(S, O)). %Built-ins are wacky things built_in(literal(S), 'http://www.w3.org/2000/10/swap/log#uri', O, Context) :- !,%ugh atom_concat('literal://', S, O). built_in(S,'http://www.w3.org/2000/10/swap/log#uri', literal(S), Context). built_in(literal(S), 'http://www.w3.org/2000/10/swap/string#startsWith', literal(O), Context) :- % write('S: '), write_ln(S), % write('O: '), write_ln(O), atom_concat(O, _, S). built_in(S, 'http://www.w3.org/2000/10/swap/string#split', O, Context) :- rdf(S, rdf:type, daml:'List'), rdf(S, daml:first, String), rdf(S, daml:rest, Second), rdf(Second, daml:first, Delim), %Could have a check for only two elements string_split(String, Delim, O, Context). %not a real predicate, but you get the idea string_split(literal(String), literal(Delim), O, Context) :- concat_atom(List, Delim, String), literalize_list(List, L_list), rdf_gen_id(anon_, O), n3_assert_list(L_list, O, Context). literalize_list([],[]). literalize_list([H|T], [literal(H)|New_t]) :- literalize_list(T, New_t). n3_assert_list([], List_id, Context) :- rdf_assert(List_id, daml:rest, daml:nil, Context). n3_assert_list([F|R], List_id, Context) :- rdf_assert(List_id, rdf:type, daml:'List', Context), rdf_assert(List_id, daml:first, F, Context), rdf_gen_id(anon_, New_list_id), rdf_assert(List_id, daml:rest, New_list_id, Context), n3_assert_list(R, New_list_id, Context). %("http://example.org/#blargh" "#") string:split ?x . % ?x : ("http://example.org/" "blargh") %[ a daml:List; daml:first "http://example.org/#blargh"; daml:rest % [daml:first "#"; daml:rest daml:nil ] ] is_built_in(P) :- nonvar(P), clause(built_in(_, P, _,_), _). %%%%%%Utils%%%%%%% nr_triples(Rdf_db, Nr) :- findall(_X, rdf(_X, _, _, Rdf_db), _Xs), length(_Xs, Nr).