Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Concatting a list of strings in Prolog

I'm writing a Lisp to C translator and I have a problem with handling strings. This is a code that transforms an unary Lisp function to a C equivalent:

define(F) --> fun_unary(F), !.

fun_unary(F) --> "(define (", label(Fun), spaces, label(Arg1), ")", spaces, expr(Body), ")",
  {swritef(F, "data *%t(data *%t) { return(%t); }", [Fun, Arg1, Body])}, !.


funs([F])  --> define(F), !.
funs([F|Fs]) --> define(F), spaces, funs(Fs), !.

Now I want to read any number of functions and return them as a single string. The above funs is the best I could come up with, but it works like this:

?- funs(F, "(define (carzero l) (= (car l) 0)) (define (zero n) (= 0 n))", []).
F = ["data *carzero(data *l) { return(eq(car(l), make_atom_int(0))); }", "data *zero(data *n) { return(eq(make_atom_int(0), n)); }"].

While I want something like this:

F = "data *carzero(data *l) { return(eq(car(l), make_atom_int(0))); }\n\ndata *zero(data *n) { return(eq(make_atom_int(0), n)); }".

so that I can nicely swritef is into a complete program, between #includes and main(). An alternative solution is to modify the highest level translator to handle the list. It curently looks like this:

program(P) --> define(F), {swritef(P, "#include \"lisp2c.h\" \n\n%t \nint main() { return 0; }", [F])}, !.

How would I do any of these two? I'm using SWI Prolog.

like image 251
Igor Avatar asked Jan 16 '11 21:01

Igor


People also ask

How do you concatenate lists in Prolog?

It can be done by using append. concatenate(List1, List2, Result):- append(List1, List2, Result). Hope this helps. Save this answer.

Are strings lists in Prolog?

As of SWI-Prolog version 7, text enclosed in double quotes (e.g., "Hello world" ) is read as objects of the type string. Strings are distinct from lists, which makes it possible to recognize them at runtime and print them using the string syntax: ?- write("Hello world!").

How do you create a list in Prolog?

In Prolog list elements are enclosed by brackets and separated by commas. Another way to represent a list is to use the head/tail notation [H|T]. Here the head of the list, H, is separated from the tail of the list, T, by a vertical bar. The tail of a list is the original list with its first element removed.

How do I concatenate a string in Prolog?

To append atoms, use the atom_concat/3 predicate: A='my ', B='atom', atom_concat(A, B, FinalAtom). Both links go to pages on the official SWI-Prolog documentation website.


2 Answers

Setting aside for now the purpose for which it's needed, let's write a Prolog predicate that concatenates a list of strings into one string, placing a double newline between each consecutive pair of strings (but not at the end of the output string, judging by the example that Jerry posted).

SWI-Prolog Manual: Normally I'd post "deep" links to the documentation, but the SWI-Prolog site uses a style of URL that triggers cross-site scripting (XSS) warnings with many browser/plugin combinations. So instead I'll refer than link to the appropriate section.

Section 4.22 Representing text in strings says (in part), "String objects by default have no lexical representation and thus can only be created using the predicates below or through the foreign language interface." This can be a little confusing, as SWI-Prolog writes strings as double-quoted text, but reads double-quoted text (by default) as lists of character codes.

Here's code for a predicate that concatenates the strings in a list, inserting another string Separator in between consecutive string pairs:

strSepCat([ ],_,Empty) :-
    string_to_list(Empty,[ ]).
strSepCat([H|T],Separator,StrCat) :-
    strSepCat(T,Separator,H,StrCat).

strSepCat([ ],_,StrCat,StrCat).
strSepCat([H|T],Sep,Str,Cat) :-
    string_concat(Sep,H,SepH),
    string_concat(Str,SepH,StrSepH),
    strSepCat(T,Sep,StrSepH,Cat).

Note that we've defined two predicates, strSepCat/3 and strSepCat/4. The former is defined in terms of the latter, a typical design pattern in Prolog that introduces an extra argument as an accumulator that binds to an output when recursion is complete. Such a technique is often helpful in getting a tail recursive definition.

To use the predicate strSepCat/3, we'd generally need to construct the separator string with (the escape sequence for) two newlines:

?- funs(Fs,Lisp,[ ]), string_to_list(Sep,"\n\n"), strSepCat(Fs,Sep,CProg).
like image 148
hardmath Avatar answered Sep 23 '22 13:09

hardmath


What about using DCG notation for appending the strings?

concat([]) --> [].
concat([List|Lists]) --> List, "\n\n", concat(Lists).
like image 22
mat Avatar answered Sep 23 '22 13:09

mat