如何在prolog中定义字符串连接运算符?

如何在prolog中定义字符串连接运算符?,prolog,operators,string-concatenation,Prolog,Operators,String Concatenation,我正在处理prolog中的字符串,我希望避免在规则中使用过多的临时变量 我想改变这样的东西: process_str(Str, Next) :- is_valid_pattern0(Pattern0), concat(Pattern0, Tail0, Str), concat("->", Tail1, Tail0), is_valid_pattern1(Pattern1), concat(Pattern1, Tail2, Tail

我正在处理prolog中的字符串,我希望避免在规则中使用过多的临时变量

我想改变这样的东西:

process_str(Str, Next) :-
    is_valid_pattern0(Pattern0),
    concat(Pattern0, Tail0, Str),
    concat("->", Tail1, Tail0),
    is_valid_pattern1(Pattern1),
    concat(Pattern1, Tail2, Tail1),
    concat("|", Tail2, Next).
?- process_str("foo->bar|baz", Next).
Next = [b, a, z] ;
false.
使用串联运算符定义,转换为以下内容:

process_str(Pattern0.."->"..Pattern1.."|"..Next, Next) :-
    is_valid_pattern0(Pattern0),
    is_valid_pattern1(Pattern1).
我相信它的可读性要高得多,但代价是根据操作符的定义进行更多的操作

我发现文档中谈到了,但据我所知,只能定义谓词运算符,而不能定义可以“返回值”的函数运算符(例如
+
运算符)


请告诉我为什么我错了,或者如何定义这样的串联运算符。

您可以在~/.swiplrc中定义以下对运算符:

:-op(699,xfx,:=)。%就在下面=
:-op(698,yfx,+)。%就在下面:=
Out:=左+右:-
将表达式展平到字符串(左,L字符串),
将表达式展平到字符串(右,右字符串),
原子到字符串([LStrings,RStrings],Out)。
将表达式展平为字符串(A++B,字符串):-
字符串:=A++B。
将表达式展平到字符串(术语,字符串):-
映射列表(整数,术语)
->字符串\u代码(字符串、术语)
;  术语\字符串(术语,字符串)。
然后

?-X:=`foo`++bar++帮助。
X=“foobarhelp”。
?-X:=`foo`++123+bar++帮助。
X=“foo123+bar帮助”。
请注意,整数列表有一个模糊性((反勾字符串就是…)。希望你能接受

如果使用XPCE编辑器,只需拉动菜单[Edit\Prolog preferences]并在那里添加代码段,然后重新编译(Ctrl+b)。这也适用于Windows,在Windows中,
~/.swiplrc
以另一种更适合平台的方式命名


当您为字符串表达式定义了适当的迷你语言后,您可以探索,以便在不引入新变量的情况下将表达式传递给谓词。注意,调试起来相当困难。。。您可以在中分析
升降机
以获得一些提示

您可以在~/.swiplrc中定义以下运算符对

:-op(699,xfx,:=)。%就在下面=
:-op(698,yfx,+)。%就在下面:=
Out:=左+右:-
将表达式展平到字符串(左,L字符串),
将表达式展平到字符串(右,右字符串),
原子到字符串([LStrings,RStrings],Out)。
将表达式展平为字符串(A++B,字符串):-
字符串:=A++B。
将表达式展平到字符串(术语,字符串):-
映射列表(整数,术语)
->字符串\u代码(字符串、术语)
;  术语\字符串(术语,字符串)。
然后

?-X:=`foo`++bar++帮助。
X=“foobarhelp”。
?-X:=`foo`++123+bar++帮助。
X=“foo123+bar帮助”。
请注意,整数列表有一个模糊性((反勾字符串就是…)。希望你能接受

如果使用XPCE编辑器,只需拉动菜单[Edit\Prolog preferences]并在那里添加代码段,然后重新编译(Ctrl+b)。这也适用于Windows,在Windows中,
~/.swiplrc
以另一种更适合平台的方式命名


当您为字符串表达式定义了适当的迷你语言后,您可以探索,以便在不引入新变量的情况下将表达式传递给谓词。注意,调试起来相当困难。。。您可以在中分析提升机以获得一些提示

这里有一个使用DCG和在SWI Prolog中工作的术语扩展的解决方案。首先,基础:

:- set_prolog_flag(double_quotes, chars).
这确保了
“foo”
将被解释为三个字符的列表,而不是一些非标准的原子“字符串”对象

然后,假设有效的
pattern0
pattern1
匹配只是字母列表。由你来填写细节。一些基本的DCG:

letters -->
    [].
letters -->
    [Letter],
    { char_type(Letter, alpha) },
    letters.

pattern0 -->
    letters.
    
pattern1 -->
    letters.
例如:

?- phrase(pattern0, Pattern0).
Pattern0 = [] ;
Pattern0 = ['A'] ;
Pattern0 = ['A', 'A'] ;
Pattern0 = ['A', 'A', 'A'] ;
Pattern0 = ['A', 'A', 'A', 'A'] ;
Pattern0 = ['A', 'A', 'A', 'A', 'A'] .

?- phrase(pattern0, "helloworld").
true.
此外,方便的DCG仅描述了一个列表:

list([]) -->
    [].
list([X | Xs]) -->
    [X],
    list(Xs).
这似乎没什么作用,但很快就会派上用场:

?- phrase(list([a, b, c]), List).
List = [a, b, c].

?- phrase(list(List), [a, b, c]).
List = [a, b, c] ;
false.
现在,您想定义一个复合模式,如
Pattern0..->“.Pattern1..”|“.Next
。我建议以不同的方式编写它,即作为子模式列表:
[pattern0,“->”,pattern1,“|”,Next]
。此类列表可能包含三种元素:

  • DCG规则名称
  • 文字字符列表
  • 可能绑定到字符列表的变量
然后,我们可以编写一个匹配某些复合模式的DCG:

composite([]) -->
    [].
composite([Head | Tail]) -->
    { atom(Head) },
    % Assume that this atom is the name of another DCG rule, and execute it.
    call(Head),
    composite(Tail).
composite([Head | Tail]) -->
    list(Head),
    composite(Tail).
这表示复合模式只描述其子模式所描述的序列。它只有两个处理子模式的子句:一个用于DCG规则名称(由原子表示),另一个用于字符列表。变量的大小写由character list子句自动处理

我们可以使用此定义将字符列表(如
“foo->bar | baz”
与复合模式匹配:

?- phrase(composite([pattern0, "->", pattern1, "|", Next]), "foo->bar|baz").
Next = [b, a, z] ;
false.
process_str(Sequence, Next) :-
    phrase(composite([pattern0, "->", pattern1, "|", Next]), Sequence).
差不多完成了!我们可以将其打包到封装模式的定义中:

?- phrase(composite([pattern0, "->", pattern1, "|", Next]), "foo->bar|baz").
Next = [b, a, z] ;
false.
process_str(Sequence, Next) :-
    phrase(composite([pattern0, "->", pattern1, "|", Next]), Sequence).
其工作原理如下:

process_str(Str, Next) :-
    is_valid_pattern0(Pattern0),
    concat(Pattern0, Tail0, Str),
    concat("->", Tail1, Tail0),
    is_valid_pattern1(Pattern1),
    concat(Pattern1, Tail2, Tail1),
    concat("|", Tail2, Next).
?- process_str("foo->bar|baz", Next).
Next = [b, a, z] ;
false.
我认为这已经相当不错了。但是如果你真的想要一种模式匹配语法,
term\u expansion
会有所帮助。它的用法(看似)简单:为
术语扩展定义一个子句(SomeTermPattern,sometherterm)
,每个与
SomeTermPattern
匹配的子句定义都将被视为程序员编写了
sometherterm
。因此:

term_expansion(
    % Replace every definition of this form:
    patterned_process_str(Pattern, Next),
    % by a replacement like this:
    patterned_process_str(Sequence, Next) :-
        phrase(composite(Pattern), Sequence)
).

patterned_process_str([pattern0, "->", pattern1, "|", Next], Next).
我们可以查看Prolog对
模式化的\u进程\u str的源代码的内部表示,以确保它符合预期:

?- listing(patterned_process_str).
patterned_process_str(B, A) :-
    phrase(composite([pattern0, [-, >], pattern1, ['|'], A]), B).
变量名丢失,但除此之外,
patterned\u process\u str
的定义扩展到了我们想要的形式,即我们为上面的
process\u str
编写的相同形式。此定义的工作原理与上面的
process\u str
完全相同(因为它是等效的):

练习:提供