Types 在Prolog中定义包含函数类型的类型层次结构

Types 在Prolog中定义包含函数类型的类型层次结构,types,prolog,swi-prolog-for-sharing,Types,Prolog,Swi Prolog For Sharing,在大学里学习过Prolog之后,我将再次访问它,并希望描述一个包含函数类型的类型层次结构。到目前为止,我得到的是(): 此程序适用于以下查询: ?- subtype(bit, int). true ?- findall(X,isa(X,int),IntTypes). IntTypes = [uint64, int64, bit, byte, uint16, uint32, int8, int16, int32] 然后,我在isa上方添加了以下函数子类型定义,其中函数是一个复杂的术语func(A

在大学里学习过Prolog之后,我将再次访问它,并希望描述一个包含函数类型的类型层次结构。到目前为止,我得到的是():

此程序适用于以下查询:

?- subtype(bit, int).
true
?- findall(X,isa(X,int),IntTypes).
IntTypes = [uint64, int64, bit, byte, uint16, uint32, int8, int16, int32]
然后,我在
isa
上方添加了以下函数子类型定义,其中函数是一个复杂的术语
func(ArgsTypeList,ResultType)

现在,我仍然能够进行一些有限检查,但即使尝试枚举
byte
的所有子类型,也会因堆栈溢出而失败

?- isa(func([int,int], bit), func([bit,bit], int)).
true
?- isa(X, byte).
X = bit ;
Stack limit (0.2Gb) exceeded

我做错了什么?

正如您所注意到的,当您添加第二组
子类型/2
定义时,问题才出现。当调用目标
isa(X,byte)
并请求第二个解决方案时,使用
isa/2
的第二个子句,导致调用
subtype/2
,两个参数都未绑定。最终,您将调用第二组
子类型/2
定义。查询中未绑定的第一个参数与
func(Args,R1)
项统一,其中两个参数都是变量。因此,递归调用最终将重复变量和
func(Args,R1)
项之间的统一,创建一个不断增加的项,并增加递归调用,最终耗尽堆栈

为了更清楚地说明这一点,请注意,请求第二个解决方案会导致对
isa/2
使用具有以下绑定的第二个子句:

isa(X,byte) :- subtype(X,Z), isa(Z, byte).
每次针对
子类型(X,Z)
目标的解决方案都会导致下一个目标
isa(Z,byte)
失败。因此,您将继续回溯到第二组
子类型/2
子句的第一个子句

理解此问题的通常解决方案是使用Prolog系统跟踪机制。出于某种原因,我无法将其与SWI Prolog一起使用,这似乎是因为您引用了SWISH而使用的,但我在GNU Prolog方面运气更好:

{trace}
| ?- isa(X, byte).
1    1  Call: isa(_279,byte) ? 
2    2  Call: subtype(_279,byte) ? 
2    2  Exit: subtype(bit,byte) ? 
1    1  Exit: isa(bit,byte) ? 

X = bit ? ;
...
17    7  Exit: subtype(func([byte|_723],int),func([bit|_723],int)) ? 
...
20    8  Exit: subtype(func([bit,byte|_839],int),func([bit,bit|_839],int)) ? 
...
21    9  Call: subtype(_806,bit) ? 
21    9  Fail: subtype(_806,bit) ? 
...

24    9  Exit: subtype(func([bit,bit,byte|_985],int),func([bit,bit,bit|_985],int)) ? 
...
25    9  Call: subtype(_806,bit) ? 
25    9  Fail: subtype(_806,bit) ? 
为了简洁起见,我省略了大部分跟踪行,但是您可以看到,正在构建一个
func/2
术语,第一个参数中的列表不断增长

如何解决这个问题?也许可以区分简单类型和复合类型?例如:

simple_subtype(bit, byte).
simple_subtype(byte, uint16).
simple_subtype(uint16, uint32).
simple_subtype(uint32, uint64).
simple_subtype(uint64, int).

simple_subtype(int8, int16).
simple_subtype(int16, int32).
simple_subtype(int32, int64).
simple_subtype(int64, int).

% Functions are covariant on the return type, and
% contravariant on the arguments' type.
compound_subtype(func(Args,R1), func(Args,R2)) :-
    simple_subtype(R1, R2).
compound_subtype(func([H1|T],R), func([H2|T],R)) :-
    simple_subtype(H2, H1).
compound_subtype(func([H|T1],R), func([H|T2],R)) :-
    compound_subtype(func(T1,R), func(T2,R)).

% subtype/2 is true if the first argument is a direct subtype of
% the second.
subtype(X,Y) :- simple_subtype(X,Y).
subtype(X,Y) :- compound_subtype(X,Y).

% isa/2 checks if there's a sequence of types that takes
% from X to Y.
isa(X,Y) :-
    subtype(X,Y).
isa(X,Y) :-
    subtype(X,Z),
    isa(Z,Y).

尽管如此,
component_subtype/2的第二和第三个子句还是有问题的,因为它们在列表的长度上没有限制…

我能够通过包含超类型的逻辑,并使用一个或另一个变量来避免无限左递归的问题,这取决于哪些变量是限制的

首先,我为简单类型定义了一个子句,明确列举了以后使用的所有类型:

simple_type(bit).
simple_type(byte).
% ...
simple_type(int).
然后,我使用
nonvar
子类型
规则仅限于第一个术语已经绑定的情况

subtype(func(Args,R1), func(Args,R2)) :-
    nonvar(R1),
    subtype(R1, R2).
subtype(func([H1|T],R), func([H2|T],R)) :-
    nonvar(H1),
    supertype(H1, H2).
subtype(func([H|T1],R), func([H|T2],R)) :-
    nonvar(T1),
    subtype(func(T1,R), func(T2,R)).
然后我定义了一个
超类型
规则,这与简单类型的
子类型
正好相反

supertype(X, Y) :-
    simple_type(X),
    subtype(Y, X).
…但函数类型完全重复

supertype(func(Args,R1), func(Args,R2)) :-
    nonvar(R1),
    supertype(R1, R2).
supertype(func([H1|T],R), func([H2|T],R)) :-
    nonvar(H1),
    subtype(H1, H2).
supertype(func([H|T1],R), func([H|T2],R)) :-
    nonvar(T1),
    supertype(func(T1,R), func(T2,R)).
isa
仍然相同,但增加了两项:

  • 一个类型和它本身是一样的(例如,一个int就是一个int)
  • 如果第一项未绑定,但第二项已绑定,请使用反向规则
    typeof
_

最后,
typeof
isa
正好相反,使用
supertype
而不是
subtype

% Functions are covariant on the return type, and
% contravariant on the arguments' type.
subtype(func(Args,R1), func(Args,R2)) :-
    subtype(R1, R2).
subtype(func([H1|T],R), func([H2|T],R)) :-
    subtype(H2, H1).
subtype(func([H|T1],R), func([H|T2],R)) :-
    subtype(func(T1,R), func(T2,R)).
typeof(X,Y) :- X = Y.
typeof(X,Y) :- supertype(X,Y).
typeof(X,Y) :-
    nonvar(X),
    supertype(X,Z),
    typeof(Z,Y).
typeof(X,Y) :-
    var(X), nonvar(Y), isa(Y,X).
我注意到这些规则有很多低效和重复的结果,但至少它起作用了:)


谢谢你的关注,但是仅仅分开它们是不够的。我希望函数也能够返回函数。在SWISH上,我发现我可以使用
跟踪,isa(X,int)。
触发调试视图。函数参数的数量和函数组合的深度是否有有效或实用的限制?如果是这样,可以修改代码以允许枚举所有可能的解决方案。感谢您的关注,我设法找到了一个包含一些代码重复的解决方案,并将其添加为答案(如果您感兴趣)。
isa(X,Y) :- X = Y.
isa(X,Y) :- subtype(X,Y).
isa(X,Y) :-
    nonvar(X),
    subtype(X,Z),
    isa(Z,Y).
isa(X,Y) :-
    var(X), nonvar(Y), typeof(Y,X).
typeof(X,Y) :- X = Y.
typeof(X,Y) :- supertype(X,Y).
typeof(X,Y) :-
    nonvar(X),
    supertype(X,Z),
    typeof(Z,Y).
typeof(X,Y) :-
    var(X), nonvar(Y), isa(Y,X).
?- setof(X, isa(func([byte, byte], uint32), X), All), length(All, L).

All = [func([bit, bit], int), func([bit, bit], uint32), func([bit, bit], uint64), func([bit, byte], int), func([bit, byte], uint32), func([bit, byte], uint64), func([byte, bit], int), func([byte, bit], uint32), func([byte, bit], uint64), func([byte, byte], int), func([byte, byte], uint32), func([byte, byte], uint64)],
L = 12