Prolog 中更安全的类型测试 [英] Safer type tests in Prolog
问题描述
ISO-Prolog(ISO/IEC 13211-1:1995,包括 Cor.1:2007、Cor.2:2012)提供 以下 用于测试术语类型的内置谓词:
ISO-Prolog (ISO/IEC 13211-1:1995 including Cor.1:2007, Cor.2:2012) offers the following built-in predicates for testing the type of a term:
1 var/1.2 原子/1.3 整数/1.4 浮动/1.5 原子/1.6 化合物/1.7 非变量/1.8 号/1.9 可调用/1.10 地/1.11 acyclic_term/1.
8.3 Type testing
1 var/1. 2 atom/1. 3 integer/1. 4 float/1. 5 atomic/1. 6 compound/1. 7 nonvar/1. 8 number/1. 9 callable/1. 10 ground/1. 11 acyclic_term/1.
在该组中,有些仅用于测试某个实例,即 8.3.1 var/1
、8.3.7 nonvar/1
,8.3.10 ground/1
,以及那些假设一个术语被充分实例化从而类型测试是安全的.不幸的是,它们与具体实例的测试结合在一起.
Within this group there are those whose purpose is solely to test for a certain instantiation, that is 8.3.1 var/1
, 8.3.7 nonvar/1
, 8.3.10 ground/1
, and those that assume that a term is sufficiently instantiated such that the type test is safe. Unfortunately, they are combined with testing for a concrete instantiation.
考虑目标 integer(X)
如果 X
是一个非整数的非变量项和当 X 时失败
是一个变量.这破坏了许多理想的声明性属性:
Consider the goal integer(X)
which fails if X
is a nonvar term that is not an integer and when X
is a variable. This destroys many desirable declarative properties:
?- X = 1, integer(X).
true.
?- integer(X), X = 1.
false.
理想情况下,第二个查询要么使用某种形式的协程,要么成功;否则它会根据 错误分类.毕竟:
Ideally the second query would either succeed using some form of coroutining ; or it would issue an instantiation error1 according to the error classification. After all:
错误按照Error_term的形式分类:
7.12.2 Error classification
Errors are classified according to the form of Error_term:
a) 当
参数或其组件之一是一个变量,并且一个
需要实例化的参数或组件.它有
表单 instantiation_error
.
...
请注意,实例化测试和类型测试的这种隐式组合会导致 Prolog 程序中以及 SO 上的许多错误.
Note that this implicit combination of instantiation testing and type testing leads to many errors in Prolog programs and also here on SO.
对这种情况的快速解决方法是在每个内置测试之前添加一个显式测试,或者详细为
A quick fix to this situation would be to add an explicit test in front of every test built-in, either verbosely as
( nonvar(T) -> true ; throw(error(instantiation_error,_)) ),
integer(T), ....
或更紧凑的
functor(T, _,_),
integer(T), ....
甚至可以
T =.. _,
integer(T), ...
我的问题有两个:
如何在用户级别提供此功能?
How to provide this functionality on the user level?
而且,让这也有点挑战性:
and, to make this also a bit challenging:
用 ISO-Prolog 编写的更安全的 atomic/1
最紧凑的实现是什么?
What is the most compact implementation of a safer
atomic/1
written in ISO-Prolog?
<小时>
1 其他不太理想的选择是循环或产生资源错误.仍然比错误的结果更可取.
推荐答案
类型测试需要区别于传统的类型测试";还隐式测试足够实例化的内置函数.因此,我们仅对充分实例化的术语 (si
) 进行有效测试.如果它们没有充分实例化,则会发出适当的错误.
The testing for types needs to distinguish itself from the traditional "type testing" built-ins that implicitly also test for a sufficient instantiation. So we effectively test only for sufficiently instantiated terms (si
). And if they are not sufficiently instantiated, an appropriate error is issued.
对于类型 nn
,因此有一个类型测试谓词 nn_si/1
和唯一的错误条件
For a type nn
, there is thus a type testing predicate nn_si/1
with the only error condition
a) 如果存在 θ 和 σ 使得 nn_si(Xθ)
是为真,nn_si(Xσ)
为假
—instantiation_error
.
a) If there is a θ and σ such that
nn_si(Xθ)
is true andnn_si(Xσ)
is false
—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
这在 Scryer 中作为 library(si)
提供.
This is available as library(si)
in Scryer.
在 SWI 中,由于其在 length/2
,改为使用:
In SWI, due to its differing behavior in length/2
, use rather:
list_si(L) :-
'$skip_list'(_, L, T),
functor(T,_,_),
T == [].
这篇关于Prolog 中更安全的类型测试的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!