测试 Prolog 术语的类型:小问题
Testing types of Prolog terms: slight problems
这里是一些测试 SWI-Prolog 术语 type/metatype 的代码:
% var,nonvar are meta-question about the state of computation, not about the term
% Note: X can be a variable (if it is fresh) or a nonvar (if it is set)
% but x can ever only be a nonvar
typeof(X, var) :- var(X),!. % if it's a variable, we don't look for any other match
typeof(X, nonvar) :- nonvar(X). % nonvar(X) is the complement of var(X)
typeof(X, int) :- integer(X). % is there a way to distinguish "machine ints" from "bigints"?
typeof(X, float) :- float(X). % IEEE 754 floats; magnitude: always double (what if long doublr arrives?)
typeof(X, number) :- number(X). % rationals are not (yet) numbers
typeof(X, rational) :- rational(X). % covers "big decimals" too
typeof(X, atom) :- atom(X).
typeof(X, atomic) :- atomic(X).
typeof(X, string) :- string(X).
typeof(X, blob(T)) :- blob(X,T).
typeof(X, compound(F,A)) :- compound(X), X =.. [F|Args], length(Args,A).
typeof(X, ground) :- ground(X).
typeof(X, cyclic) :- cyclic_term(X).
typeof(X, list(Len)) :- is_list(X),length(X,Len). % being a "list" is specific nonlocal phenomenon
typeof(X, conj(Len)) :- nonvar(X),is_conjunction(X,Len).
typeof(X, disj(Len)) :- nonvar(X),is_disjunction(X,Len).
typeof((_A->_B) , impl).
typeof(:-_A , directive).
typeof(_H:-_B , clause).
is_conjunction((_,B),Len) :- is_conjunction(B,Lb),!,Len is Lb+1.
is_conjunction((_,_),1).
is_disjunction((_;B),Len) :- is_disjunction(B,Lb),!,Len is Lb+1.
is_disjunction((_;_),1).
%
% TEST CODE
%
:- begin_tests(type_inspection).
test('empty list') :- is_this_right([] , [atomic,ground,nonvar,blob(reserved_symbol),list(0)]).
test('an atom') :- is_this_right(foo_the_atom , [atom,atomic,ground,nonvar,blob(text)]).
test('a string') :- is_this_right("foo_the_string" , [atomic,ground,nonvar,string]).
test('a variable') :- is_this_right(_VAR , [var]).
test('integer') :- is_this_right(4377 , [atomic,ground,int,nonvar,number,rational]).
test('big integer') :- is_this_right(43759624750933342417 , [atomic,ground,int,nonvar,number,rational]).
test('decimal') :- is_this_right(5600.556 , [atomic,float,ground,nonvar,number]).
test('float') :- A is 2/6, is_this_right(A, [atomic,float,ground,nonvar,number]).
test('/ compound') :- is_this_right(2/6, [ground,nonvar,compound('/',2)]).
test('float') :- is_this_right(1.234 , [atomic,float,ground,nonvar,number]).
test('rational') :- is_this_right(5r6 , [atomic,ground,nonvar,number,rational]).
test('rational') :- R is 5 rdiv 6, is_this_right(R, [atomic,ground,nonvar,number,rational]).
test('cyclic compound') :- A = a(1,2,3,A), is_this_right(A, [cyclic,ground,nonvar,compound(a,4)]).
test('dict') :- is_this_right(_{a:1,b:2}, [nonvar,compound(dict,5)]).
test('cyclic list') :- A = [1,2,3|A], is_this_right(A, [cyclic,ground,nonvar,compound(['|'],2)]).
test('nonempty list') :- is_this_right([1,2,3] , [ground,nonvar,list(3),compound(['|'],2)]).
setify(A,B,As,Bs) :- % A,B -> As,Bs
list_to_ord_set(A,As), % A->As
list_to_ord_set(B,Bs). % B->Bs
is_this_right(Value,Expected) :-
setof(T,typeof(Value,T),Ts),
verdict(Value,Expected,Ts).
verdict(Value,Expected,Got) :- % V,E,G -> b?
setify(Expected,Got,Eos,Gos),
(ord_seteq(Eos,Gos)
-> format("For ~w we have: ~w\n",[Value,Gos])
; (format("For ~w, expected ~w but got ~w\n",[Value,Eos,Gos]),fail)).
:- end_tests(type_inspection).
rt :- run_tests(type_inspection).
如果我们 运行 目标 rt
,我们得到这个(格式不正确):
这些测试通过:
For [] we have: [atomic,ground,nonvar,blob(reserved_symbol),list(0)]
For foo_the_atom we have: [atom,atomic,ground,nonvar,blob(text)]
For foo_the_string we have: [atomic,ground,nonvar,string]
For _15852 we have: [var]
For 4377 we have: [atomic,ground,int,nonvar,number,rational]
For 43759624750933342417 we have: [atomic,ground,int,nonvar,number,rational]
For 5600.556 we have: [atomic,float,ground,nonvar,number]
For 0.3333333333333333 we have: [atomic,float,ground,nonvar,number]
For 2/6 we have: [ground,nonvar,compound(/,2)]
For 1.234 we have: [atomic,float,ground,nonvar,number]
For 5r6 we have: [atomic,ground,nonvar,number,rational]
For 5r6 we have: [atomic,ground,nonvar,number,rational]
For @(S_1,[S_1=a(1,2,3,S_1)]) we have: [cyclic,ground,nonvar,compound(a,4)]
但是 |
函子的复合项有问题。我必须使用什么符号才能使测试通过?
For _15714{a:1,b:2},
expected [nonvar,compound(dict,5)]
but got [nonvar,compound(dict,5)]
For @(S_1,[S_1=[1,2,3|S_1]]),
expected [cyclic,ground,nonvar,compound([|],2)]
but got [cyclic,ground,nonvar,compound([|],2)]
For [1,2,3], expected [ground,nonvar,list(3),compound([|],2)]
but got [ground,nonvar,list(3),compound([|],2)]
此外,有没有办法区分"big integers"和"machine integers"(除了检查星等?)
您应该使用 ~q
来写术语(即写引号),而不是 ~w
。尝试:
verdict(Value,Expected,Got) :- % V,E,G -> b?
setify(Expected,Got,Eos,Gos),
( ord_seteq(Eos,Gos)
-> format("For ~q we have: ~q\n",[Value,Gos])
; format("For ~q, expected ~q but got ~q\n",[Value,Eos,Gos]),
fail
).
否则您可能会误导结果的解释:
For _4414{a:1,b:2},
expected [nonvar,compound(dict,5)]
but got [nonvar,compound(C'dict',5)]
ERROR: user://1:68:
test dict: failed
For @(S_1,[S_1=[1,2,3|S_1]]),
expected [cyclic,ground,nonvar,compound(['|'],2)]
but got [cyclic,ground,nonvar,compound('[|]',2)]
ERROR: user://1:69:
test cyclic list: failed
For [1,2,3],
expected [ground,nonvar,list(3),compound(['|'],2)]
but got [ground,nonvar,list(3),compound('[|]',2)]
ERROR: user://1:70:
test nonempty list: failed
注意:
?- functor([1,2,3], Functor, Arity).
Functor = '[|]',
Arity = 2.
?- functor(key{a:1,b:2}, Functor, Arity).
Functor = C'dict',
Arity = 5.
为什么? SWI-Prolog 更改了传统和标准的 '.'/2
列表仿函数,以便它可以将其用于字典。由于解析方式的不同,Dicts 的仿函数看起来很奇怪。
这里是一些测试 SWI-Prolog 术语 type/metatype 的代码:
% var,nonvar are meta-question about the state of computation, not about the term
% Note: X can be a variable (if it is fresh) or a nonvar (if it is set)
% but x can ever only be a nonvar
typeof(X, var) :- var(X),!. % if it's a variable, we don't look for any other match
typeof(X, nonvar) :- nonvar(X). % nonvar(X) is the complement of var(X)
typeof(X, int) :- integer(X). % is there a way to distinguish "machine ints" from "bigints"?
typeof(X, float) :- float(X). % IEEE 754 floats; magnitude: always double (what if long doublr arrives?)
typeof(X, number) :- number(X). % rationals are not (yet) numbers
typeof(X, rational) :- rational(X). % covers "big decimals" too
typeof(X, atom) :- atom(X).
typeof(X, atomic) :- atomic(X).
typeof(X, string) :- string(X).
typeof(X, blob(T)) :- blob(X,T).
typeof(X, compound(F,A)) :- compound(X), X =.. [F|Args], length(Args,A).
typeof(X, ground) :- ground(X).
typeof(X, cyclic) :- cyclic_term(X).
typeof(X, list(Len)) :- is_list(X),length(X,Len). % being a "list" is specific nonlocal phenomenon
typeof(X, conj(Len)) :- nonvar(X),is_conjunction(X,Len).
typeof(X, disj(Len)) :- nonvar(X),is_disjunction(X,Len).
typeof((_A->_B) , impl).
typeof(:-_A , directive).
typeof(_H:-_B , clause).
is_conjunction((_,B),Len) :- is_conjunction(B,Lb),!,Len is Lb+1.
is_conjunction((_,_),1).
is_disjunction((_;B),Len) :- is_disjunction(B,Lb),!,Len is Lb+1.
is_disjunction((_;_),1).
%
% TEST CODE
%
:- begin_tests(type_inspection).
test('empty list') :- is_this_right([] , [atomic,ground,nonvar,blob(reserved_symbol),list(0)]).
test('an atom') :- is_this_right(foo_the_atom , [atom,atomic,ground,nonvar,blob(text)]).
test('a string') :- is_this_right("foo_the_string" , [atomic,ground,nonvar,string]).
test('a variable') :- is_this_right(_VAR , [var]).
test('integer') :- is_this_right(4377 , [atomic,ground,int,nonvar,number,rational]).
test('big integer') :- is_this_right(43759624750933342417 , [atomic,ground,int,nonvar,number,rational]).
test('decimal') :- is_this_right(5600.556 , [atomic,float,ground,nonvar,number]).
test('float') :- A is 2/6, is_this_right(A, [atomic,float,ground,nonvar,number]).
test('/ compound') :- is_this_right(2/6, [ground,nonvar,compound('/',2)]).
test('float') :- is_this_right(1.234 , [atomic,float,ground,nonvar,number]).
test('rational') :- is_this_right(5r6 , [atomic,ground,nonvar,number,rational]).
test('rational') :- R is 5 rdiv 6, is_this_right(R, [atomic,ground,nonvar,number,rational]).
test('cyclic compound') :- A = a(1,2,3,A), is_this_right(A, [cyclic,ground,nonvar,compound(a,4)]).
test('dict') :- is_this_right(_{a:1,b:2}, [nonvar,compound(dict,5)]).
test('cyclic list') :- A = [1,2,3|A], is_this_right(A, [cyclic,ground,nonvar,compound(['|'],2)]).
test('nonempty list') :- is_this_right([1,2,3] , [ground,nonvar,list(3),compound(['|'],2)]).
setify(A,B,As,Bs) :- % A,B -> As,Bs
list_to_ord_set(A,As), % A->As
list_to_ord_set(B,Bs). % B->Bs
is_this_right(Value,Expected) :-
setof(T,typeof(Value,T),Ts),
verdict(Value,Expected,Ts).
verdict(Value,Expected,Got) :- % V,E,G -> b?
setify(Expected,Got,Eos,Gos),
(ord_seteq(Eos,Gos)
-> format("For ~w we have: ~w\n",[Value,Gos])
; (format("For ~w, expected ~w but got ~w\n",[Value,Eos,Gos]),fail)).
:- end_tests(type_inspection).
rt :- run_tests(type_inspection).
如果我们 运行 目标 rt
,我们得到这个(格式不正确):
这些测试通过:
For [] we have: [atomic,ground,nonvar,blob(reserved_symbol),list(0)]
For foo_the_atom we have: [atom,atomic,ground,nonvar,blob(text)]
For foo_the_string we have: [atomic,ground,nonvar,string]
For _15852 we have: [var]
For 4377 we have: [atomic,ground,int,nonvar,number,rational]
For 43759624750933342417 we have: [atomic,ground,int,nonvar,number,rational]
For 5600.556 we have: [atomic,float,ground,nonvar,number]
For 0.3333333333333333 we have: [atomic,float,ground,nonvar,number]
For 2/6 we have: [ground,nonvar,compound(/,2)]
For 1.234 we have: [atomic,float,ground,nonvar,number]
For 5r6 we have: [atomic,ground,nonvar,number,rational]
For 5r6 we have: [atomic,ground,nonvar,number,rational]
For @(S_1,[S_1=a(1,2,3,S_1)]) we have: [cyclic,ground,nonvar,compound(a,4)]
但是 |
函子的复合项有问题。我必须使用什么符号才能使测试通过?
For _15714{a:1,b:2},
expected [nonvar,compound(dict,5)]
but got [nonvar,compound(dict,5)]
For @(S_1,[S_1=[1,2,3|S_1]]),
expected [cyclic,ground,nonvar,compound([|],2)]
but got [cyclic,ground,nonvar,compound([|],2)]
For [1,2,3], expected [ground,nonvar,list(3),compound([|],2)]
but got [ground,nonvar,list(3),compound([|],2)]
此外,有没有办法区分"big integers"和"machine integers"(除了检查星等?)
您应该使用 ~q
来写术语(即写引号),而不是 ~w
。尝试:
verdict(Value,Expected,Got) :- % V,E,G -> b?
setify(Expected,Got,Eos,Gos),
( ord_seteq(Eos,Gos)
-> format("For ~q we have: ~q\n",[Value,Gos])
; format("For ~q, expected ~q but got ~q\n",[Value,Eos,Gos]),
fail
).
否则您可能会误导结果的解释:
For _4414{a:1,b:2},
expected [nonvar,compound(dict,5)]
but got [nonvar,compound(C'dict',5)]
ERROR: user://1:68:
test dict: failed
For @(S_1,[S_1=[1,2,3|S_1]]),
expected [cyclic,ground,nonvar,compound(['|'],2)]
but got [cyclic,ground,nonvar,compound('[|]',2)]
ERROR: user://1:69:
test cyclic list: failed
For [1,2,3],
expected [ground,nonvar,list(3),compound(['|'],2)]
but got [ground,nonvar,list(3),compound('[|]',2)]
ERROR: user://1:70:
test nonempty list: failed
注意:
?- functor([1,2,3], Functor, Arity).
Functor = '[|]',
Arity = 2.
?- functor(key{a:1,b:2}, Functor, Arity).
Functor = C'dict',
Arity = 5.
为什么? SWI-Prolog 更改了传统和标准的 '.'/2
列表仿函数,以便它可以将其用于字典。由于解析方式的不同,Dicts 的仿函数看起来很奇怪。