0

One can easily consult a Prolog file using consult/1 or [filename]..

Suppose I generate Prolog code as an atom. I can in a predicate write that code to a file and then consult it, and query a predicate from that code, e.g.

example :-
    generate_stuff(X),
    write_to_file(X,'filename.pl'),
    consult('filename.pl'),
    predicate_in_filename.

How would I go about doing the same thing but without writing X (the code) to a file? I'm having no luck with assert which takes a term as input whereas here I have complete code in an atom.

Fatalize
  • 3,513
  • 15
  • 25
  • `consult` asserts the terms that are in `filename.pl`. You could write a predicate that parses through `X` and asserts the terms. There are lots of Prolog support predicates to extract terms. It's not clear how you've structured or use `generate_stuff/1` overall, but it might make more sense for `generate_stuff` to assert the terms as they're created rather than collect them all as a giant string and parse through them afterwards. – lurker Jul 09 '16 at 13:59
  • @lurker Is there any predicate that parses `X` into terms? `read_term_from_atom/3` only parses the first one and it would be cumbersome for me to rewrite something that separates terms in an atom. – Fatalize Jul 09 '16 at 14:01
  • 1
    If you are structuring your code to create your "stuff" as one big string (which I recommend against if possible), then check out the SWI prolog [Term reading and writing](http://www.swi-prolog.org/pldoc/man?section=termrw) predicates. Consider setting up `X` as a stream rather than a file. – lurker Jul 09 '16 at 14:04
  • At the very least, why can't `generate_stuff` create a list of terms or clauses? – lurker Jul 09 '16 at 14:16
  • @lurker Say `rw` should generate a predicate that reverses then write the input. I read the first char, i generate `reverse(Input,V0)`, then I call recursively the parser and append `,\nwrite(V0)`, then `.`. I don't see how I can do the same thing easily with terms instead of simply appending atoms with each other. – Fatalize Jul 09 '16 at 14:21
  • By "list of terms" I meant a list of atoms (or strings) that would individually each represent a single term, rather than one long atom representing all of the terms. It appears that's where your solution went based upon the answer you posted. – lurker Jul 09 '16 at 16:30

2 Answers2

3

The clean way is of course to not even produce an atom in the first place, but a more structured representation from the start.

However, if you really want to use atoms and later treat them as structured terms, use atom_to_term/3, then assert the clause.

For example:

?- atom_to_term('p(X, Y) :- dif(X, Y)', T, Vs).
T =  (p(_G925, _G926):-dif(_G925, _G926)),
Vs = ['X'=_G925, 'Y'=_G926].

In your case, you can simply ignore Vs:

?- atom_to_term('p(X, Y) :- dif(X, Y)', T, _).
T =  (p(_G916, _G917):-dif(_G916, _G917)).
mat
  • 40,498
  • 3
  • 51
  • 78
  • The problem is what if I have multiple terms in the atom? e.g. `'a.\nb.'`. Here I could split on new lines and maplist atom_to_term but it's not that easy if I have linebreaks inside terms too (for readability). – Fatalize Jul 09 '16 at 14:04
  • @Fatalize then see my latest comment to your question. – lurker Jul 09 '16 at 14:05
  • 1
    You should really reconsider your basic representation. Avoid using atoms for structured data. The same goes for strings by the way: They are almost always the wrong representation. – mat Jul 09 '16 at 14:06
0

For posterity, here is how I did it, provided that you have only one term in each atom of the list:

%...
maplist(read_term_from_atom_, ListOfAtoms, ListOfTerms),
maplist(asserta, ListOfTerms),
%...

read_term_from_atom_(A, B) :-
    read_term_from_atom(A, B, []).
Fatalize
  • 3,513
  • 15
  • 25
  • This is less general than it could be: You can use `_` instead of `[]` and also allow *variables* in the clauses. – mat Jul 09 '16 at 18:10