关于Prolog语法

3
有时我会看到这样的术语: X = a:b 或 X = a-b
我可以发出请求,例如 X = Y:Z 编译器将Y与a统一,Z与b统一,如预期的那样。
现在我的问题是: 我可以使用哪些字符(或字符序列)来组合两个Prolog原子?!
也许您可以给我一些有关此问题的进一步信息链接。
感谢您的帮助和来自德国的亲切问候。
3个回答

4
“我可以使用哪些字符(或字符序列)来组合两个Prolog原子?”您所询问的是Prolog的整个运算符语法定义。要获得完整答案,请参阅标签iso-prolog,了解如何获取Prolog标准ISO/IEC 13211-1的完整信息。
但是,作为一个简短的开端,可以回答:
Prolog语法由以下内容组成:
1.函数表示法,例如+(a,b),加号。 2.可动态重新定义的运算符语法。 3.一些额外的内容。
看起来您想知道哪些“字符”可以用作运算符。
“简短的答案”是您可以使用所有原子Op,这些原子对于current_op(Pri,Fix,Op)成功。因此,您可以动态地询问哪些运算符存在:
?- current_op(Pri, Fix, Op).
   Pri = 1, Fix = fx, Op = ($)
;  Pri = 1150, Fix = fx, Op = (module_transparent)
;  Pri = 700, Fix = xfx, Op = (=@=)
;  Pri = 700, Fix = xfx, Op = (@>=)
;  Pri = 700, Fix = xfx, Op = (>=)
; ... .

所有这些运算符都可以按指定的方式使用,作为前缀、中缀或后缀,并具有指定的优先级。其中一些运算符是特定于SWI的,而一些是由标准定义的。上面,只有@>=>=是标准运算符。

大多数运算符仅由图形字符#$&*+-./:<=>?@^~或以小写字母开头的字母、数字和下划线组成。有两个独立的字符!;,还有更特殊的,|。与上述不同的运算符名称需要引用-您很少会遇到它们。

要查看运算符的嵌套方式,请使用write_canonical(Term)

长答案是您也可以自己定义这样的运算符。但是,请注意更改运算符语法通常会有许多非常难以理解的影响。更重要的是,由于许多系统在某些很少使用的配置方面存在差异。例如,您提到的系统,SWI在几个方面存在差异

我建议在学习更多关于Prolog语言之前避免定义新的运算符。


3

让我们看看 X = Y:Z 的内部结构。

?- display( X = Y:Z ).
=(_G3,:(_G1,_G2))
true.

然后我们有一个嵌套结构,其中functor是运算符。

运算符是一个原子,原子语法规则表示我们有3种类型要考虑:

  • 任何可打印字符序列,用单引号括起来
  • 仅包含特殊字符的序列,其中特殊字符是`.=:-+*/><#@~?(我希望我已经找到了所有这些字符,您可以从此页面检查是否有遗漏!)
  • 以小写字母/大写字母或下划线开头的字符序列

编辑

functor(缩写为函数构造器,在Prolog上下文中使用函数会产生误导)是将多个参数“绑定”在一起的符号。参数的数量称为arity。在Prolog中,一个术语是一个原子文字(如数字或原子),或者是一个递归结构,由一个functor和若干个参数组成,每个参数本身都是一个术语(至少1个)。

给定适当的声明,即op / 3,可以将一元和二元术语表示为表达式,就像您展示的那个一样。

使用:特殊字符的运算符示例是“:-”

member(X,[X|_]).
member(X,[_|T]) :- member(X, T).

为了更方便地查看术语结构而不使用运算符语法,您可以使用ISO Prolog标准的write_canonical/1谓词来实现更便携的解决方案。 - Paulo Moura
谢谢 Paulo,你是对的。 我之前习惯使用 write_canonical/1,但今天早上(或昨天?)我注意到 Jan 使用的是 display/1,这我不知道。 它比 write_canonical 更容易记住... - CapelliC
首先,非常感谢您的有用评论!它们对我帮助很大!如果我理解正确,在上面的例子中“:”字符是一个函数符?!而在这种情况下,函数符(什么是函数符?!)就是运算符,对吗?现在还有一个问题:除了“:”之外,我可以使用哪些其他字符,就像在示例中一样。 - mrbela
“:”并不是一个“特殊”的字符,就像您所写的那样。它是像 #$&*+-./:<=>?@^~` 一样的图形字符。 - false
运算符有很多“特殊”字符。 - false

1

原话是:“O.P.说(我引用):”

有时我看到像这样的术语:X = a:bX = a-b

我可以做请求,如X = Y:Z,编译器将Y与a对应,并将Z与b对应,符合预期。

现在我的答案是:我可以使用哪些字符(或字符序列)来组合两个Prolog原子?!

简短的回答是:几乎任何你想要的(只要它是一个原子)

更长的答案是:

你看到的是中缀(x infix_op b)、前缀(pfx_op b)和后缀(b sfx_op运算符。任何具有2元数的结构都可以是中缀运算符。任何具有1元数的结构都可以是前缀或后缀运算符。因此,任何原子都可以是运算符。

Prolog使用以优先级驱动的递归下降解析器进行解析(当然是用Prolog编写)。 运算符和它们的优先级、结合性被定义并列举在operator/3谓词中。结合性关系到解析树的构造。像a-b-c这样的表达式可以解析为(a-(b-c))(右结合),或((a-b)-c)(左结合)。
优先级关系到操作符的紧密程度。像a+b*c这样的表达式以(a+(b*c)的形式绑定,不是因为结合性,而是因为* / 2(乘法)具有比+ / 2(加法)更高的优先级。
您可以随心所欲地添加、删除和更改操作符。尽管如此,这并不能给您无限制地打破Prolog语法的机会。
但应该注意,任何操作符表达式也可以通过普通符号表示法来书写:
a + b * c

完全相同的

'+'( a , '*'(b,c) )

+(a, *(b,c)) 中,没有引用 +* 的理由。 - false
引用原子不会有任何影响,反而可以提高理解。functor/arity 是指示谓词或结构名称和元数的常规方式,例如 'foo/2'。这不是 Prolog 语法:'*'/2 表示“名称为 *,元数为 2 的谓词或结构”。 - Nicholas Carey
标准的方法是在函数符为运算符时写括号,就像我所指示的那样。引用曾经(大约30年前)是一种禁用运算符的惯例,但它从未流行起来。 - false

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接