在子句头中使用vars解构(Prolog)

在子句头中使用vars解构(Prolog),prolog,pattern-matching,Prolog,Pattern Matching,我目前正在使用SWI Prolog编写一些代码。几年前,当我使用Prolog时,我可以发誓我能够在子句头中将变量名设置为“解构”,但现在它似乎对我不起作用(至少在SWI Prolog中是这样) 例如: example(X = [Row|Rows]) :- do_something_with_x(X), do_something_with_row(Row), ... 我想把它称为,例如,示例([1,2,3]),我想让X和[Row | Rows]与谓词

我目前正在使用SWI Prolog编写一些代码。几年前,当我使用Prolog时,我可以发誓我能够在子句头中将变量名设置为“解构”,但现在它似乎对我不起作用(至少在SWI Prolog中是这样)

例如:

    example(X = [Row|Rows]) :-
      do_something_with_x(X), 
      do_something_with_row(Row),
      ...
我想把它称为,例如,
示例([1,2,3])
,我想让
X
[Row | Rows]
与谓词体中的同一谓词的参数匹配,即第一个参数(这里是
[1,2,3]

有人知道这是否可行吗?

您可以随时写:

example([Row|Rows]) :-
  do_something_with_x([Row|Rows]),
  do_something_with_row(Row),
  ...

下面是一段只打印其参数的愚蠢代码。它这样做是为了显示参数是什么,并激怒纯粹主义者:

example(X = [H|T]) :-
    format("X: ~w; H: ~w; T: ~w~n", [X, H, T]).
现在您可以使用它:

?- example(List = [a,b,c]).
X: _9150; H: a; T: [b,c]
true.

?- example(foo = [bar|baz]).
X: foo; H: bar; T: baz
true.

?- example(X).
X: _8700; H: _8706; T: _8708
X =  (_8700=[_8706|_8708]).

等等。玩玩它。但是你仍然需要解释你真正想要用你的程序实现什么。

事实上,这是Prolog中缺少的功能(在Haskell中,它被称为“模式”;在
foo(x@(a:b))=…
x
指的是整个,而
a
b
指的是它的各个部分)

你能做的最接近的事情就是

pred(X) :- X = [A|B], 
    ... .
而且

pred(X, [A|B]) :- 
    ... . 
虽然总是使用两次使用的同一事物调用它:
Z=,pred(Z,Z),…

继续这个想法,你实际上可以定义

pred( X = [A|B], ... ) :- ... .
如您所愿,注意始终这样称呼:
Z=,pred(Z=Z,…)
。您甚至可以定义一些元谓词来自动进行转换,如

call_at( Pred, Arg ) :- call(Pred, Arg = Arg).

这里的
=
本身是语法的,它的使用协议赋予它特殊的含义,即语义。用Lisp的话来说,Prolog的术语总是没有价值的,象征性的。

是的,我知道。但是,有可能在子句头中这样做吗?或者我记得我的序言错了(我已经有一段时间没有使用它了)?@user1992634在我未经训练的眼里,它看起来像是在子句头中。您应该解释上面示例的语义。您能否尝试提供预期的含义,可能是伪代码?@User9213,我所说的是我代码的子句头中的“X=”部分。你可以将其与保罗·莫拉的代码进行比较,后者没有。我以为是Prolog允许的。我不知道我是否遇到了bug,是否只是SWI Prolog的问题,或者。。。如果Prolog确实不允许它。@user1992634是的,Prolog允许它,但问题是它意味着什么。看我的答案。不,你不能。从句的头部与目标(从句的主体)是统一的,而统一就是你所说的解构,并将以
=
@capelical调用。我真的不明白你想说什么:-(我不知道这是一个语法问题还是另一个问题。对不起,解释不是很清楚,但意思应该是可以理解的。无论如何,这不是禁止的语法,但它不是你想要的。解构(和构造)都包含在统一中,统一总是在头部执行的,即所谓的模式匹配/2调用以执行显式统一作为目标。@capelical我现在理解了。但我理解是因为我理解了您正在使用的词汇表,并且我已经知道您试图解释的内容。我怀疑OP可能在这方面有问题。@capelical“…您完全可以将
=/2
定义为
=(a,a).
:)好吧,我想要实现的就是节省屏幕空间和少一行代码。我不想用一行代码来写“X=…”当我能在头脑中实现这一点时。我用Erlang这样的语言来实现。当我在SWI Prolog中尝试它时,它会给我带来问题。有时它会起作用,有时不会。如果其他人没有提供更好的答案,我会接受你的答案。你在使用什么Prolog?是的,你在子句头部中使用了它,但你也在使用它n在运行程序时查询。我不想这样做,我只想在子句头中这样做。@user1992634请看最后一个查询。我没有在那里使用任何
=
。但是,我不知道如何表述它,以便您理解我的话的含义,但我会再试一次:您正在解决什么具体问题?“我不想使用一行代码”或“我用Erlang这样的语言做这个(什么?)不是编程问题;这是你个人的愿望。它们不能帮助我理解你的程序应该做什么。这与
=
或头或体无关。@User9213 OP想要Haskell的功能(事实证明,Erlang也拥有它们)。@意志清晰中有优雅;它无法与那种只试图遮住心灵之眼的优雅相提并论。应该可以使用术语扩展来获取谓词子句,如
p(X as Y):-r(X)。
并将其重写为
p(Y):-r(Y)
。我不确定这是否是个好主意,但我想在我尝试之前我不会知道。我已经解决了好几次这个问题;与你的建议相反,干净的解决方案是编写
p([a | B]):-X=[a | B],…
因为通常头部的模式匹配是有用且必要的,但有时当你只需要整个东西时,继续在身体中书写
[A | B]
感觉很愚蠢。你的意思与第一个建议相反。对,同意。因此,使用双参数,或
p(X=[A | B]):-…
,头脑中有模式匹配。我的Lisp程序员总是对不必要的考虑非常谨慎,这很可笑……他们会对你说,“考虑太可怕了!“…因此,也许正确的答案是您的建议,只是在Prolog中根本不使用as模式。有些模式比这更复杂,还有嵌套模式等。实际上,将同一复杂代码复制两次不是好的做法。这是关于