Xariez
Xariez

Reputation: 789

Prolog - load 2D array from text file into program

I'm currently working on a Prolog program which would, logically, have some kind of "save/load" feature. I've gotten the save part to work, where I'm now (as a start) creating three *.txt files, which will contain a 2D array/list each. However, I'm facing some issues trying to load it back into the program.

What I have right now is something as simple as:

% Initialize globals
?- nb_setval(aisles_global, []).  

% Load all previously saved data from the given .txt files
load_all():-
    exists_file('C:\\Users\\Xariez\\Desktop\\aisles.txt'),
    open('C:\\Users\\Xariez\\Desktop\\aisles.txt', read, InAisles),

    read_line_to_codes(InAisles, AisleString),
    % read_line_to_string(InAisles, AisleString),
    writeln(AisleString),
    nb_setval(aisles_global, AisleString),

    close(InAisles).

As previously mentioned, the files will have a 2D array each, but as an example:

aisles.txt

[["Beer", "Cider" ], [ "Milk", "Juice" ], ["Light Bread", "Dark Bread"]]

I've tried using both read_line_to_codes/2 and read_line_to_string/2. While it technically works when reading it into codes, I feel like it would quickly become annoying to reconstruct a 2D list/array since it's now got every character as a code. And while reading into a string succeeds in the reading part, we now have a string that LOOKS like a list, but isn't really one (if I've understood this situation correctly?). And hence I'm here.

If anyone got any ideas/help, that'd be greatly appreciated. Thanks!

Upvotes: 0

Views: 148

Answers (1)

Isabelle Newbie
Isabelle Newbie

Reputation: 9378

Prolog has predicates for doing input/output of terms directly. You don't need to roll these yourself. Reading terms is done using read, while for writing there are several options.

Your best shot for writing is probably write_canonical, which will write terms in "canonical" syntax. This means that everything is quoted as needed (for example, an atom 'A' will be printed as 'A' and not as plain A like write would print it), and terms with operators are printed in prefix syntax, which means you get the same term even if the reader doesn't have the same operators declared (for example, x is y is printed as is(x, y)).

So you can write your output like:

dump(Aisles, Filename) :-
    open(Filename, write, OutAisles),
    write_canonical(OutAisles, Aisles),
    write(OutAisles, '.'),
    close(OutAisles).

Writing the . is necessary because read expects to read a term terminated by a period. Your reading predicate could be:

load(Aisles, Filename) :-
    open(Filename, read, InAisles),
    read(InAisles, Aisles),
    close(InAisles).

Running this using some example data:

?- aisles(As), dump(As, aisles).
As = [["Beer", "Cider"], x is y, 'A', _G1380, ["Milk", "Juice"], ["Light Bread", "Dark Bread"]].

?- load(As, aisles).
As = [["Beer", "Cider"], x is y, 'A', _G1338, ["Milk", "Juice"], ["Light Bread", "Dark Bread"]].

The contents of the file, as you can check in a text editor, is:

[["Beer","Cider"],is(x,y),'A',_,["Milk","Juice"],["Light Bread","Dark Bread"]].

Note the canonical syntax for is. You should almost certainly avoid writing variables, but this shouldn't be a problem in your case.

Upvotes: 1

Related Questions