1

如果我在数据库中有一个简单的谓词,有没有一种方法可以请求以特定顺序(asc/desc)返回结果,而不必将它们全部读入内存并执行 sort/2 或执行 setof /3?

例如,考虑这个数据库:

animal(dog).
animal(cat).
animal(elephant).
animal(bird).
animal(aardvark).

我想以某种方式在第一个术语中将动物声明为已排序的 ASC,以便我可以像这样简单地查询它:

?- animal(X).
X = aardvark ;
X = bird ;
X = cat ;
X = dog ;
X = elephant ;
No.

能够做到这一点对于将我的知识库更像传统数据库来处理会非常方便。

4

2 回答 2

2

不,如果您不阅读它们,就无法对它们进行排序。

Ofc 您可以编写排序的谓词或生成排序的谓词:

findall(sorted_animal(X),animal(X),Animals),
sort(Animals,SAnimals),
maplist(assertz(X),SAnimals),
compile_predicates([sorted_animal]/1).

或者

findall(animal(X),animal(X),Animals),
sort(Animals, SAnimals),
retractall(animal(X)),
maplist(assertz(X),SAnimals),
compile_predicates([sorted_animal]/1).

但是您必须将谓词声明animal/1为动态的:

:-dynamic(animal/1).
animal(dog).
....

(在代码文件中)

我曾经compile_predicates/1提高速度;但是,这意味着您不能在该谓词上使用assert/1orretract/1再次,因此如果您添加/删除动物,请跳过它。

或者,您可以使用有序集并将其作为参数传递

于 2012-09-05T00:13:08.953 回答
1

Prolog 掩盖了复杂的排序问题,为 DB 访问、FIFO 或 LIFO 规定了严格的时间顺序模型,默认为 FIFO。这是合理的,因为这种访问定义了计算模型。

所以没有标准的方法来改变子句检索顺序。

我认为goal_expansion /2 可以用来引入这样的特性,我会尝试一个原型。但我不确定我会得到任何有用的东西......

编辑

第一次尝试,但使用缓慢(但更简单)的收回/断言。

/*  File:    order_by.pl
    Author:  Carlo,,,
    Created: Sep  5 2012
    Purpose: sort fact
*/
:- module(order_by,
      [order_by/2
      ]).

order_by(PredicateIndicator, Argument) :-
    (   PredicateIndicator = Module:Functor/Arity
    ;   PredicateIndicator = Functor/Arity, Module = user
    ),
    length(EmptyArgs, Arity),
    P =.. [Functor|EmptyArgs],
    findall(P, retract(Module:P), L),
    predsort(by_arg(Argument), L, S),
    maplist(assert_in_module(Module), S).

assert_in_module(Module, P) :-
    assertz(Module:P).

by_arg(Argument, Delta, E1, E2) :-
    arg(Argument, E1, A1),
    arg(Argument, E2, A2),
    (   A1 @< A2
    ->  Delta = <
    ;   Delta = >
    ).

测试文件(我只在用户模块中测试过),请注意:-动态声明是强制性的:

/*  File:    order_by_test.pl
    Author:  Carlo,,,
    Created: Sep  5 2012
    Purpose:
*/
:- [order_by].
:- dynamic animal/1.

animal(dog).
animal(cat).
animal(elephant).
animal(bird).
animal(aardvark).

test :-
    order_by(animal/1, 1),
    forall(animal(X), writeln(X)).

测试结果:

?- test.
aardvark
bird
cat
dog
elephant
于 2012-09-05T05:28:41.563 回答