Concatting список строк в прологе
Я пишу Lisp для переводчика C, и у меня проблема с обработкой строк. Это код, который преобразует унарную функцию Lisp в эквивалент C:
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), !.
теперь я хочу прочитать любое количество функций и вернуть их в виде одной строки. Выше funs
это лучшее, что я мог придумать, но это работает так:
?- 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)); }"].
в то время как я хочу что-то вроде этого:
F = "data *carzero(data *l) { return(eq(car(l), make_atom_int(0))); }nndata *zero(data *n) { return(eq(make_atom_int(0), n)); }".
так что я могу красиво swritef
входит в полную программу, между #include
s и main (). Альтернативным решением является изменение переводчика самого высокого уровня для обработки списка. Это выглядит так:
program(P) --> define(F), {swritef(P, "#include "lisp2c.h" nn%t nint main() { return 0; }", [F])}, !.
как бы я сделал любой из этих двух? Я использую SWI Prolog.
3 ответов
отложив пока цель, для которой это необходимо, давайте напишем предикат Пролога, который объединяет список строк в одну строку, помещая двойную новую строку между каждой последовательной парой строк (но не в конце выходной строки, судя по примеру, который опубликовал Джерри).
руководство SWI-Prolog: обычно я бы разместил" глубокие " ссылки на документация, но сайт SWI-Prolog использует стиль URL, который запускает кросс-сайт предупреждения сценариев (XSS) со многими комбинациями браузера/плагина. Поэтому вместо этого я буду ссылаться, чем ссылка на соответствующий раздел.
вот код для предиката, который объединяет строки в списке, вставляя другой разделитель строк между последовательными парами строк:
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).
обратите внимание, что мы определили два предиката,strSepCat / 3 и strSepCat / 4. Первый определяется в терминах последнего, типичного шаблона проектирования в Prolog, который вводит дополнительный аргумент как аккумулятор который привязывается к выходу, когда рекурсия полный. Такая техника часто помогает получить хвост рекурсивной определение.
использовать предикат strSepCat / 3, нам обычно нужно построить строку разделителя с (escape-последовательностью для) двух новых строк:
?- funs(Fs,Lisp,[ ]), string_to_list(Sep,"\n\n"), strSepCat(Fs,Sep,CProg).
Как насчет использования обозначения DCG для добавления строк?
concat([]) --> [].
concat([List|Lists]) --> List, "\n\n", concat(Lists).
поскольку строки в прологе действительно являются списками кодов символов, вы можете использовать append
в пользовательском предикате, который также вставляет новые строки:
concat_program([], "").
concat_program([L|Ls], Str) :-
concat_program(Ls, Str0),
append("\n\n", Str0, Str1),
append(L, Str1, Str).
использование:
funs(Fs, Lisp, []),
concat_program(Fs, P),
write("#include ...\n"),
writef(P).