为什么我们使用“!"在序言中 [英] Why do we use '!' in prolog

查看:64
本文介绍了为什么我们使用“!"在序言中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我试图理解的代码.

This is the code that i am trying to understand.

co(X) :- co(X,[],L).
co([],A,A):- write(A).
co([X|Xs], A, L) :- p(X-Z,A,R), !, Z1 is Z+1, co(Xs, [X-Z1|R], L). 
co([X|Xs], A, L) :- co(Xs, [X-1|A], L). 

p(X-Y,[X-Y|R],R):- !.
p(X,[H|Y], [H|Z]) :- p(X,Y,Z).

'!'有什么用和上面代码中的谓词 p(,,) .或者任何人都可以在上述代码的每个步骤中添加注释,以便我能够理解.谢谢.

What is the use of '!' and predicate p(,,) in the above code. OR Can anybody just add comments in every step of the above code so that i can able to understand . Thanks.

推荐答案

在您的程序中有很多事情需要解决.削减甚至不是主要问题.请把扫帚拿来.

There are many things to address in your program. Cuts are not even the major concern. Please, bring me the broom.

您所追求的精确界面是什么?co(Xs) 目前的目的是产生副作用.否则,对于给定的列表,它可能会成功或失败.但不止于此.然而,这种副作用根本不需要——而且在大多数情况下不是一种有用的方法,因为这样的程序实际上是不可重用的,并且无视任何逻辑推理.你需要留下一个漏洞,让一些结果潜伏在关系中.添加另一个参数并删除 co/3 中的目标 write/1.

What is the precise interface you are after? The purpose of co(Xs) currently, is to produce a side effect. Otherwise it can succeed or fail for a given list. But not more than that. Yet, this side effect is not at all needed - and is for most situations not a helpful approach, since such a program is practically unreusable and defies any logical reasoning. You need to leave a hole to let some result lurk out of the relation. Add another argument and remove the goal write/1 in co/3.

co(Xs, D) :-
   co(Xs, [], D).

现在您可以单独使用顶级 shell 测试程序.您不需要任何线束或沙箱来检查输出".它就在那里,很容易在单独的论证中.

Now you can test the program with the top-level shell alone. You do not need any harness or sandbox to check for the "output". It is there, readily in a separate argument.

接下来是 co/3 本身.在这里,最好的办法是通过将关注点分开来澄清意图,并使这些额外的论点更能揭示意图.D 代表字典.另一个好名字是 KVs,意思是键值对的列表(复数 s).请注意不同状态的编号方式:它们以 D0D1、...开头,最后是 D.以这种方式,如果您开始编写规则,您可以将 D0,D 放在头部,而无需知道该规则中需要多少个状态.

Next is co/3 itself. Here, the best is to clarify the intention by separating a bit the concerns, and making these extra arguments a bit more intention-revealing. D stands for dictionary. Another good name would be KVs meaning list (the plural s) of key-value pairs. Note how the different states are numbered: They start with D0, D1, ... and at the end there is D. In this manner, if you start to write a rule, you can put D0,D already in the head without knowing how many states you will need in that rule.

co([], D,D).
co([X|Xs], D0,D) :-
   nn(X, D0,D1),
   co(Xs, D1,D).

nn(K, D0,D) :-
   p(K-V0,D0,D1), !,
   V is V0+1,
   D = [X-V|D1].
nn(K, D0,D) :-
   D = [K-1|D0].

p(X-Y,[X-Y|R],R):- !.
p(X,[H|Y], [H|Z]) :- p(X,Y,Z).

co/3 现在更清楚地揭示了它的意图.它以某种方式将列表的元素与某个更新"的状态相关联.对于每个元素.有一句话是这样的:这是左折.甚至还有一个谓词:foldl/4.所以我们可以同样定义 co/3 为:

co/3 now more clearly reveals its intention. It somehow relates the elements of a list to some state that is "updated" for each element. There is a word for this: This is a left-fold. And there is even a predicate for it: foldl/4. So we could equally define co/3 as:

co(Xs, D0,D) :-
   foldl(nn, Xs, D0,D).

或者更好地完全摆脱 co/3:

or better get rid of co/3 altogether:

co(Xs, D) :-
   foldl(nn, Xs, [], D).

foldl(_C_3, [], S,S).
foldl(C_3, [X|Xs], S0,S) :-
   call(C_3, X, S0,S1),
   foldl(C_3, Xs, S1,S).

请注意,到目前为止,我什至没有碰过你的任何片段,这些现在是他们的最后时刻......

Note, that so far, I have not even touched any cuts of yours, these are now their last moments...

p/3 中的删减没有任何作用.无论如何,在目标 p/3 之后立即有一个削减.那么,p/3 中就不需要 X-Y,你可以放心地用另一个变量替换它.简而言之,p/3 现在是谓词 select/3 来自 Prolog 序言.

The cut in p/3 does not serve any purpose. There is a cut immediately after the goal p/3 anyway. Then, X-Y is not needed in p/3, you can safely replace it by another variable. In short, p/3 is now the predicate select/3 from the Prolog prologue.

select(E, [E|Xs], Xs).
select(E, [X|Xs], [X|Ys]) :-
   select(E, Xs, Ys).

nn(K, D0,D) :-
   select(K-V0, D0,D1), !,
   V is V0+1,
   D = [K-V|D1].
nn(K, D0,D) :-
   D = [K-1|D0].

剩下的这一部分不能轻易删除:如果K-V不出现在D中,它可以保护替代子句不被使用.但是,仍然有更好的方式来表达这一点.

This one remaining cut cannot be removed so easily: it protects the alternate clause from being used should K-V not occur in D. However, there are still better ways to express this.

nn(K, D0,D) :-
   select(K-V0, D0,D1),
   V is V0+1,
   D = [K-V|D1].
nn(K, D0,D) :-
   \+select(K-_, D0,_),
   D = [K-1|D0].

现在,每个规则都说明了它自己想要什么.这意味着,我们现在可以自由更改这些规则的顺序.称之为迷信,但我更喜欢:

Now, each rule states what it wants for itself. This means, that we can now freely change the order of those rules. Call it superstition, but I prefer:

nn(K, D0,D) :-
   \+select(K-_, D0,_),
   D = [K-1|D0].
nn(K, D0,D) :-
   select(K-V0, D0,D1),
   V is V0+1,
   D = [K-V|D1].

使用 dif/2

净化

为了使之成为真正的关系,我们需要摆脱这种否定.与其说没有解决方案,不如说我们可以要求所有键(键是 Key-Value 中的第一个参数)与 K 不同.

Purify with dif/2

To make this into a true relation, we need to get rid of this negation. Instead of saying, that there is no solution, we can instead demand that all keys (key is the first argument in Key-Value) are different to K.

nokey(_K, []).
nokey(K, [Kx-|KVs]) :-
   dif(K, Kx),
   nokey(K, KVs).

nn(K, D,[K-1|D]) :-
   nokey(K, D).
nn(K, D0,[K-V|D]) :-
   select(K-V0, D0,D),
   V is V0+1.

lambdas 的帮助下,nokey(K, D) 变成了 <代码>地图列表(K+\(Kx-_)^dif(Kx,K), D)

With the help of lambdas, nokey(K, D) becomes maplist(K+\(Kx-_)^dif(Kx,K), D)

总而言之,我们现在有:

To summarize, we have now:

co(Xs, D) :-
   foldl(nn, Xs, [], D).

nn(K, D,[K-1|D]) :-
   maplist(K+\(Kx-_)^dif(Kx,K), D).
nn(K, D0,[K-V|D]) :-
   select(K-V0, D0,D),
   V is V0+1.

那么这个关系是什么:第一个参数是一个列表,第二个参数是一个键值列表,每个元素和列表中出现的次数.

So what is this relation about: The first argument is a list, and the second argument a Key-Value list, with each element and the number of occurrences in the list.

这篇关于为什么我们使用“!"在序言中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆