Prolog - 列表的异常 cons 语法

问题描述 投票:0回答:3

我在 Lee Naish 的论文Prolog 中的高阶逻辑编程 中遇到了一些不熟悉的 Prolog 语法。这是论文中的第一个代码示例:

% insertion sort (simple version)
isort([], []).
isort(A.As, Bs) :-
    isort(As, Bs1),
    isort(A, Bs1, Bs).

% insert number into sorted list
insert(N, [], [N]).
insert(N, H.L, N.H.L) :-
    N =< H.
insert(N, H.LO, H.L) :-
    N > H,
    insert(N, LO, L).

我对

A.As
中的
isort(A.As, Bs) :-
感到困惑。从上下文来看,它 appears 是列表的替代 cons 语法,相当于
isort([A|As], Bs) :-
.

以及

N.H.L
似乎是一个更方便的说法
[N|[H|L]]
.

但是 SWI Prolog 不会接受这种不寻常的语法(除非我做错了什么)。

有人认识吗?我的假设正确吗?哪个 Prolog 解释器接受它作为有效语法?

prolog iso-prolog
3个回答
33
投票

点运算符在 1972 年的第一个 Prolog 系统中用于列表,用 Algol-W 编写,有时称为 Prolog 0。它受到 LISP 系统中类似符号的启发。以下示例来自 Alain Colmerauer 和 Philippe Roussel 的论文Prolog 的诞生——Prolog 的创造者。

+ELEMENT(*X, *X.*Y).
+ELEMENT(*X, *Y.*Z) -ELEMENT(*X, *Z).

当时

[]
曾经是
NIL
。在下一个版本中都保持不变Prolog I由 Battani & Meloni 用 Fortran 编写。

然后 DECsystem 10 Prolog 使用 case 来区分原子和变量,并引入了方括号符号,将

nil
X.Xs
替换为
[]
[X,..Xs]
,在 DECsystem 10 的更高版本中,将
[X|Xs]
作为替代。在 ISO Prolog 中,只有
[X|Xs]
.(X,Xs)
,以及作为规范的语法
'.'(X,Xs)
.

请注意,点在 ISO Prolog 中有许多不同的作用。它已经作为

  • end token 后跟

    %
    或 SPACE、NEWLINE、TAB 等布局字符。

  • 浮点数中的小数点,如

    3.14159

  • 图形标记字符形成图形标记为

    =..

因此,如果您现在将

.
声明为中缀运算符,则必须非常小心。包括您编写的内容和 Prolog 系统将读取的内容。一个额外的空格可以改变术语的含义。考虑两种表示法的两个数字列表:

[1,2.3,4]. [5].
1 .2.3.4.[]. 5.[].

请注意,您必须在

1
后添加一个空格。在这种情况下,数字前面的额外空格可能会改变您的术语的含义。像这样:

[1|2.3]. [4]. 5. [].
1 .2.3. 4.[]. 5. [].

这是另一个可能更有说服力的例子:

[1,-2].
1.(-2).[].

负数需要点列表中的圆括号。

今天,只有 YAP 和 XSB 仍然默认提供中缀

.
——而且他们的做法有所不同。而且 XSB 甚至不识别上面的点语法:你需要用圆括号括起一些非负数。

你写道,

N.H.L
似乎是说
[N|[H|L]]
的更方便的方式。有一个简单的经验法则来简化 ISO Prolog 中的此类表达式:每当您在列表中看到标记
|
[
紧挨着彼此时,您可以用
,
替换它们(并删除相应的
]
在右侧)。所以你现在可以写:
[N,H|L]
看起来 that bad.

您也可以在另一个方向使用该规则。如果我们有一个列表

[1,2,3,4,5]
,我们可以像这样使用
|
作为“刀片”:
[1,2,3|[4,5]]
.


另一条评论,因为您正在阅读 Naish 的论文:与此同时,很好理解只需要

call/N
!并且ISO Prolog支持
call/1
 call/2
call/8
.


9
投票

是的,你是对的,点是列表cons中缀运算符。它实际上是 ISO Prolog 标准所要求的,但通常是隐藏的。我前段时间发现(并使用)了这种语法:

:- module(eog, []).
:- op(103, xfy, (.)).

% where $ARGS appears as argument, replace the call ($ARGS) with a VAR
% the calle goes before caller, binding the VAR (added as last ARG)
funcs(X, (V, Y)) :-
    nonvar(X),
    X =.. W.As,

    % identify meta arguments
    (   predicate_property(X, meta_predicate M)
        % explicitly exclude to handle test(dcg)
        % I'd like to handle this case in general way...
    ,   M \= phrase(2, ?, ?)
    ->  M =.. W.Ms
    ;   true
    ),

    seek_call(As, Ms, Bs, V),
    Y =.. W.Bs.

% look for first $ usage
seek_call([], [], _Bs, _V) :-
    !, fail.
seek_call(A.As, M.Ms, A.Bs, V) :-
    M @>= 0, M @=< 9, % skip meta arguments
    !, seek_call(As, Ms, Bs, V).
seek_call(A.As, _, B.As, V) :-
    nonvar(A),
    A = $(F),
    F =.. Fp.FAs,
    (   current_arithmetic_function(F) % inline arith
    ->  V = (PH is F)
    ;   append(FAs, [PH], FBs),
        V =.. Fp.FBs
    ),
    !, B = PH.
seek_call(A.As, _.Ms, B.As, V) :-
    nonvar(A),
    A =.. F.FAs,
    seek_call(FAs, Ms, FBs, V),
    !, B =.. F.FBs.
seek_call(A.As, _.Ms, A.Bs, V) :-
    !, seek_call(As, Ms, Bs, V).

:- multifile user:goal_expansion/2.
user:goal_expansion(X, Y) :-
    ( X = (_ , _) ; X = (_ ; _) ; X = (_ -> _) )
    -> !, fail % leave control flow unchanged (useless after the meta... handling?)
    ;  funcs(X, Y).

/* end eog.pl */

有人建议我反对。实际上,[A|B] 语法是 .运营商,引入可读性。

OT:那是什么密码?

上面的代码是我尝试用函数使 Prolog 变甜的尝试。即,根据要求,通过

$
,引入算术表达式所需的临时变量(例如)

fact(N, F) :-
     N > 1 -> F is N * $fact($(N - 1)) ; F is 1.

每个 $ 引入一个变量。展开后,我们有一个更传统的事实/2

?- listing(fact).
plunit_eog:fact(A, C) :-
    (   A>1
    ->  B is A+ -1,
        fact(B, D),
        C is A*D
    ;   C is 1
    ).

我们有很多表达方式,这可能很有用......


8
投票

此语法来自 NU-Prolog。见这里。它可能只是普通的列表仿函数 '.'/2 重新定义为中缀运算符,不需要尾随空列表:

?- L= .(a,.(b,[])).
L = [a,b]
Yes (0.00s cpu)
?- op(500, xfy, '.').
Yes (0.00s cpu)
?- L = a.b.[].
L = [a,b]
Yes (0.00s cpu)
© www.soinside.com 2019 - 2024. All rights reserved.