Prolog中更安全的类型测试

时间:2014-12-04 23:54:31

标签: prolog iso-prolog

ISO-Prolog(ISO / IEC 13211-1:1995,包括Cor.1:2007,Cor.2:2012)提供the following内置谓词来测试术语的类型:

  

8.3类型测试

     

1个VAR / 1。 2原子/ l。 3整数/ 1。浮子4/1。 5原子/ l。 6化合物/ 1。 7 nonvar / 1。 8号/ 1。 9可调用/ 1。 10接地/ 1。 11 acyclic_term / 1。

在这个组中,有些人的目的仅仅是测试某个实例化,即8.3.1 var/1,8.3.7 nonvar/1,8.3.10 ground/1,以及那些假设一个术语被充分实例化以使类型测试是安全的。不幸的是,它们与测试具体实例相结合。

如果integer(X)是一个不是整数的非变数术语而}是X的变量,则会考虑失败的目标X。这破坏了许多理想的声明性属性:

?- X = 1, integer(X).
true.

?- integer(X), X = 1.
false.

理想情况下,第二个查询要么使用某种形式的coroutining成功;或者根据error classification发出实例化错误 1 。毕竟:

  

7.12.2错误分类

     

根据Error_term的形式对错误进行分类:

     
    

a)当有一个实例化错误时      参数或其中一个组件是一个变量,和一个      实例化的参数或组件是必需的。它有      表格instantiation_error

  
     

...

请注意,实例化测试和类型测试的这种隐式组合会导致Prolog程序中的许多错误,并且也会出现在SO上。

对这种情况的快速解决方法是在内置的每个测试前添加一个显式测试,或者详细说明

   ( var(T) -> throw(error(instantiation_error,_)) ; true),
   integer(T), ....

或更紧凑地

functor(T, _,_),
integer(T), ....

它可能是偶数

T =.. _,
integer(T), ...

我的问题有两个:

  

如何在用户级别提供此功能?

并且,为了使这也有点挑战:

  

用ISO-Prolog编写的更安全atomic/1的最紧凑的实现是什么?


1其他不太理想的选择是循环或产生资源错误。仍然比不正确的结果更可取。 功能

2 个答案:

答案 0 :(得分:3)

对类型的测试需要区别于传统的“类型测试”内置函数,这些内置函数也隐式地测试了足够的实例化。因此,我们仅针对充分实例化的术语(si)进行有效测试。如果它们没有充分实例化,则会发出适当的错误。 对于类型nn,因此存在具有唯一错误条件的类型测试谓词nn_si/1

  

a)如果有θ和σ,nn_si(Xθ)是   是,nn_si(Xσ)是假的 -   instantiation_error

atom_si(A) :-
   functor(A, _, 0),    % for the instantiation error
   atom(A).

integer_si(I) :-
   functor(I, _, 0),
   integer(I).

atomic_si(AC) :-
   functor(AC,_,0).

list_si(L) :-
   \+ \+ length(L, _),  % for silent failure
   sort(L, _).          % for the instantiation error

在SWI中,由于length/2中的行为不同,请使用:

list_si(L) :-
    '$skip_list'(_, L, T),
    functor(T,_,_),
    T == [].

答案 1 :(得分:2)

这是一种非常天真的尝试,可以实现您建议的解决方案。

首先,has_type(Type, Var)成功,或者因实例化错误而失败:

has_type(Type, X) :-
    var(X), !,
    throw(error(instantiation_error, _)).
has_type(Type, X) :-
    nonvar_has_type(Type, X).

nonvar_has_type(atom, X) :- atom(X).
nonvar_has_type(integer, X) :- integer(X).
nonvar_has_type(compound, X) :- compound(X).
% etc

其次,could_be(Type, Var)(类似于must_be/2)使用coroutining来允许查询在将来的某个时间点成功:

could_be(Type, X) :-
    var(X), !,
    freeze_type(Type, X).
could_be(Type, X) :-
    nonvar_has_type(Type, X).

freeze_type(integer, X) :- freeze(X, integer(X)).
freeze_type(atom, X) :- freeze(X, atom(X)).
freeze_type(compound, X) :- freeze(X, compound(X)).
% etc

这种方法有几点不足之处,但您的意见可能有助于我更好地理解用例。

编辑:开"类型"在Prolog

Prolog中的类型,正如我所理解的那样,不是"类型"它们只是可以在运行时查询的信息,而且存在是因为它是对底层实现的有用的漏洞抽象。

我唯一能够实际使用"类型"已去过"标记"我的变量,如复合词number(1)number(pi)operator(+)date(2015, 1, 8)等。然后我可以将变量放在那里,编写确定性或半确定性谓词,理解我的代码在一周后看到它时的意思....

所以自由变量和整数只是条件;主要是因为,正如你的问题非常巧妙地指出的那样,自由变量可以变成整数,或原子,或复合词。您可以使用coroutining来确保自由变量只能成为某种类型"类型"术语后来,但从实际的角度来看,这仍然不如使用复合词。

我极有可能在这里混淆不同的问题;说实话,我对Prolog的经验充其量是有限的。我刚刚阅读了我正在使用的实现的文档,并试图找到使用它的最佳方式。