在 Prolog 中连接字符串列表

发布于 2024-10-12 17:37:53 字数 1144 浏览 11 评论 0原文

我正在编写一个 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 变成一个完整的程序,在#include 和main() 之间。另一种解决方案是修改最高级别的转换器来处理该列表。目前看起来是这样的:

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

我将如何做这两者中的任何一个?我正在使用 SWI 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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

终止放荡 2024-10-19 17:37:53

现在先把它的用途放在一边,让我们编写一个 Prolog 谓词,将字符串列表连接成一个字符串,在每对连续的字符串之间放置一个双换行符(但不是在输出字符串的末尾,根据杰瑞发布的示例)。

SWI-Prolog 手册:通常我会发布“深层”链接到 文档,但 SWI-Prolog 站点使用的 URL 样式会通过许多浏览器/插件组合触发跨站点脚本 (XSS) 警告。因此,我将参考而不是链接到相应的部分。

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

以下是连接列表中的字符串的谓词代码,在连续的字符串对之间插入另一个字符串分隔符:

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/3strSepCat/4< /强>。前者是根据后者定义的,这是 Prolog 中的典型设计模式,它引入了一个额外的参数作为累加器,当递归完成时该累加器绑定到输出。这种技术通常有助于获得尾递归定义。

要使用谓词 strSepCat/3,我们通常需要使用两个换行符(的转义序列)构造分隔符字符串:

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

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).
吻风 2024-10-19 17:37:53

使用 DCG 表示法附加字符串怎么样?

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

What about using DCG notation for appending the strings?

concat([]) --> [].
concat([List|Lists]) --> List, "\n\n", concat(Lists).
怪异←思 2024-10-19 17:37:53

比接受的答案更简单(也更通用)的解决方案是使用reduce 和现有的 string_concat 作为参数:

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笔记本:https://swish.swi-prolog.org/p/reduce.swinb

A simpler (and more generic) solution than the accepted answer is to use reduce with the existing string_concat as a parameter:

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.org/p/reduce.swinb

明明#如月 2024-10-19 17:37:53

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

Since strings in Prolog are really lists of character codes, you can use append in a custom predicate that also inserts the newlines:

concat_program([], "").
concat_program([L|Ls], Str) :-
    concat_program(Ls, Str0),
    append("\n\n", Str0, Str1),
    append(L, Str1, Str).

Usage:

funs(Fs, Lisp, []),
concat_program(Fs, P),
write("#include ...\n"),
writef(P).
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文