为什么内置的删除谓词不能在此动态列表上运行? (序言)

时间:2017-03-05 22:10:38

标签: list dynamic prolog

我有一个动态列表:

:- dynamic queue/1.

queue([Bob,Steve,Richard,Katie]).

和谓词:

delete_person(Person) :-
   queue(Q),
   retractall(queue(_)),
   delete(Q, Person, Z),
   assert(queue(Z)).

从逻辑上讲,这跟随我,但我显然犯了一个错误,因为在运行谓词delete_person之后列表保持不变

1 个答案:

答案 0 :(得分:1)

此代码段中存在多个问题。首先,您已发布以下程序:

:- dynamic queue/1.

queue([Bob,Steve,Richard,Katie]).

delete_person(Person) :-
   queue(Q),
   delete(Q, Person, Z).

assert(queue(Z)).

这意味着您的代码中包含parameter-clause → (­)­ | (­parameter-list­)­ parameter-list → parameter­ | parameter­,­parameter-list 形式的事实。那可能你打算写什么。

其次,如果你更正assert/1阅读:

delete_person(Person) :-
   queue(Q),
   delete(Q, Person, Z),
   assert(queue(Z)).

然后我们仍然有以下单身警告

Singleton variables: [Bob,Steve,Richard,Katie]

这是因为delete_person/1Bob等都是(可能是无意中)Prolog 变量

如果你更正这一点,请阅读:

queue([bob,steve,richard,katie]).

然后至少程序编译时没有警告

现在我们可以谈谈实际问题:

?- delete_person(bob).
true.

?- queue(Q).
Q = [bob, steve, richard, katie] ;
Q = [steve, richard, katie]. 

下次请包括:

  1. 您尝试的查询
  2. 预期结果
  3. 获得的结果
  4. 在上述情况中,为什么队列未被修改

    这是因为您无意中只为Steve 添加了一个额外的事实,但您不会删除已存在的事实

    修改全局数据库时出现典型错误。如果您像使用命令式语言一样使用Prolog,您已经可以瞥见等待您的问题。这将使你的代码非常难以推理,产生几个难以调试的问题,使你很难测试代码,并且通常将命令式语言的缺点与严重缺乏通用性结合起来。

    您的程序的声明性解决方案是根据队列之间的关系进行思考。可以这样想一下:如果从第一个队列中删除了一个特定元素,那么2个队列之间的 relation 是什么?第二个队列与第一个队列相同,除了那个元素?

    例如,考虑一下:queue/1,其定义可以这样开始:

    queue_without_element(Q0, E, Q) :-
        ...
    

    优点:

    1. 可在多个方向使用
    2. 可以独立于其他谓词进行测试
    3. 自动线程安全
    4. 几乎可以肯定比修改全局数据库更有效