Generics &引用;“通用编程”;在序言中

Generics &引用;“通用编程”;在序言中,generics,prolog,polymorphism,parametric-polymorphism,Generics,Prolog,Polymorphism,Parametric Polymorphism,据我所知,Prolog没有任何用于的内置机制。可以使用统一来模拟泛型,但这需要在运行时进行类型检查: :- initialization(main). :- set_prolog_flag(double_quotes, chars). % this is a "generic" predicate, where A and B have the same type add(A,B,C) :- generic_types([A:Type,B:Type]), (Type = num

据我所知,Prolog没有任何用于的内置机制。可以使用统一来模拟泛型,但这需要在运行时进行类型检查:

:- initialization(main).
:- set_prolog_flag(double_quotes, chars).

% this is a "generic" predicate, where A and B have the same type
add(A,B,C) :-
    generic_types([A:Type,B:Type]),
    (Type = number,
    C is A + B;Type=var,C = A+B).

main :-
    add(A,B,C),
    add(3,4,D),
    writeln(C),
    writeln(D).

generic_types([]).
generic_types([A:B|C]) :-
    member(B,[var,nonvar,float,rational,number,atom,atomic,compound,callable,ground,acyclic_term]),
    call(B,A),
    generic_types(C).
has_type(Type,A) :-
    call(Type,A).

是否可以在运行时编写“泛型”谓词而不检查每个变量的类型?

您可以通过将类型参数显式添加到谓词来模拟参数多态性:

:- protocol(math_protocol).

    :- public(add/3).

:- end_protocol.
:- object(number,
    implements(math_protocol)).

    add(A, B, C) :-
        C is A + B.

:- end_object.


:- object(var,
    implements(math_protocol)).

    add(A, B, C) :-
        C = A + B.

:- end_object.
add(int,A,B,C):-
C是A+B。
加上(var、A、B、C):-
C#=A+B。
?添加(变量2、3、5)。
对。
?-添加(var、A、3、5)。
A=2。
?添加(int,A,3,5)。
错误:参数没有充分实例化

Prolog中通过Logtalk提供了一些形式的通用编程,Logtalk扩展了Prolog,可用于大多数Prolog系统

鉴于您希望根据前两个参数的类型使用不同的
add/3
谓词定义,我们可以从定义声明谓词的协议开始:

:- protocol(math_protocol).

    :- public(add/3).

:- end_protocol.
:- object(number,
    implements(math_protocol)).

    add(A, B, C) :-
        C is A + B.

:- end_object.


:- object(var,
    implements(math_protocol)).

    add(A, B, C) :-
        C = A + B.

:- end_object.
根据您的示例代码,我们现在可以为谓词定义不同的实现:

:- protocol(math_protocol).

    :- public(add/3).

:- end_protocol.
:- object(number,
    implements(math_protocol)).

    add(A, B, C) :-
        C is A + B.

:- end_object.


:- object(var,
    implements(math_protocol)).

    add(A, B, C) :-
        C = A + B.

:- end_object.
我们可以修改
number
var
对象来执行类型检查。例如:

:- object(number,
    implements(math_protocol)).

    add(A, B, C) :-
        number(A),
        number(B),
        C is A + B.

:- end_object.
:- object(math(_Type_),
    implements(math_protocol)).

    add(A, B, C) :-
        call(_Type_, A),
        call(_Type_, B),
        _Type_::add(A, B, C).

:- end_object.
或者,我们可以在执行类型检查的类型上定义一个对象参数,然后委托对该类型的实际操作。例如:

:- object(number,
    implements(math_protocol)).

    add(A, B, C) :-
        number(A),
        number(B),
        C is A + B.

:- end_object.
:- object(math(_Type_),
    implements(math_protocol)).

    add(A, B, C) :-
        call(_Type_, A),
        call(_Type_, B),
        _Type_::add(A, B, C).

:- end_object.
在这种情况下,示例调用为:

?- math(number)::add(2, 3, Sum).
Sum = 5
yes
但请注意,这些替代方案仍将在运行时执行类型检查


可以修改参数化对象以查找示例代码中的参数类型。但是,如果没有允许查询术语类型的内置Prolog谓词(没有标准,通常也不可用),那么这是非常低效的。

Prolog是动态类型的。所以没有太多的类型检查,就像Python一样。这有点像询问如何在自动变速器汽车中模拟离合器。“泛型编程”本身仅适用于具有静态类型检查的语言。就其接受的类型而言,每个Prolog谓词都已经是泛型的,并且在Prolog中除了运行时之外没有其他类型的检查。Python和其他所有动态类型语言中的情况都是一样的。Python的“类型系统”在设计上对Python程序的语义或它们的评估没有任何影响。有关详细信息,请参阅。您也可以使用Prolog的,而不是将类型作为参数传递。