在Prolog中并列一个字符串列表

问题描述 投票:6回答:4

我正在写一个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))); }\n\ndata *zero(data *n) { return(eq(make_atom_int(0), n)); }".

这样我就可以很好地 swritef 是成一个完整的方案,在 #includes和main()。另一种解决方案是修改最高级别的翻译器来处理列表。它目前的样子是这样的。

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

我怎么才能完成这两个任务?我使用的是SWI Prolog,我正在写一个Lisp到C的翻译器。

prolog artificial-intelligence translation grammar dcg
4个回答
4
投票

暂且不考虑需要它的目的,让我们写一个Prolog谓词,将一个字符串列表连接成一个字符串,在每一对连续的字符串之间放置一个双换行(但不是在输出字符串的末尾,从Jerry发布的例子来看)。

SWI-Prolog手册。 通常我会发布 "深层 "链接到 文件但是SWI-Prolog网站使用了一种URL风格,在许多浏览器插件组合中会触发跨站点脚本(XSS)警告。 所以我将参考而不是链接到相应的章节。

第4.22节用字符串表示文本说(部分):"默认情况下,字符串对象没有词法表示,因此只能使用下面的谓词或通过外语接口创建。" 这可能会让人有些困惑,因为SWI-Prolog将字符串写成双引号文本,但将双引号文本(默认情况下)读成字符代码列表。

这里是一个谓词的代码,它将字符串连接到一个列表中,在连续的字符串对之间插入另一个字符串Separator。

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).

请注意,我们定义了两个谓词: strSepCat3strSepCat4. 前者是用后者来定义的,这是Prolog中典型的设计模式,它引入了一个额外的参数作为 蓄能器 当递归完成时,它与一个输出绑定。 这样的技术通常有助于获得一个 递推 定义。

要使用谓词 strSepCat3我们一般需要用(转义序列的)两个换行符来构造分隔符字符串。

?- funs(Fs,Lisp,[ ]), string_to_list(Sep,"\n\n"), strSepCat(Fs,Sep,CProg).

2
投票

那用DCG符号来附加字符串呢?

concat([]) --> [].
concat([List|Lists]) --> List, "\n\n", concat(Lists).

1
投票

由于Prolog中的字符串实际上是字符代码的列表,你可以使用 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).

0
投票

一个比公认的答案更简单(也更通用)的解决方案是用现有的string_concat作为参数使用reduce。

reduce3(_, [],  Default, Default).
reduce3(_, [A], _, A).
reduce3(P3, [A,B|T], _, D):-
    call(P3, A, B, C),
    reduce3(P3, [C|T], _, D).
?- reduce3(string_concat, ["123", "456", "789"], "", R).
R = "123456789"
?- reduce3(string_concat, ["123"], "", R).
R = "123"
?- reduce3(string_concat, [], "", R).
R = ""
strings_concat(Strings, String):-
    reduce3(string_concat, Strings, "", String).

SWISH notebook: https:/swish.swi-prolog.orgpreduce.swinb

© www.soinside.com 2019 - 2024. All rights reserved.