【问题标题】:"Generic programming" in PrologProlog中的“通用编程”
【发布时间】:2020-01-22 08:55:41
【问题描述】:

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

:- 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).

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

【问题讨论】:

  • Prolog 是动态类型的。所以没有太多的类型检查,就像在 Python 中一样。
  • 这有点像问如何模拟自动变速器汽车的离合器。 “通用编程”本身仅适用于具有静态类型检查的语言。每个 Prolog 谓词就其接受的类型而言已经是通用的,并且除了运行时之外,Prolog 中没有其他类型的类型检查。在 Python 和其他所有动态类型语言中,情况都是一样的。 Python 的“类型系统”在设计上对 Python 程序的语义或其评估没有任何影响。
  • 一个小评论:在你的情况下有意义的类型包括var。请参阅this 了解更多信息。

标签: generics prolog polymorphism parametric-polymorphism


【解决方案1】:

通过 Logtalk 在 Prolog 中提供了某些形式的通用编程,它扩展了 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.

我们可以修改numbervar 对象来执行类型检查。例如:

:- 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 谓词,这是非常低效的(没有标准,而且通常也不可用)。

【讨论】:

    【解决方案2】:

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

    add(int, A, B, C) :-
        C is A + B.
    add(var, A, B, C) :-
        C #= A + B.
    
    
    ?- add(var, 2, 3, 5).
    true.
    
    ?- add(var, A, 3, 5).
    A = 2.
    
    ?- add(int, A, 3, 5).
    ERROR: Arguments are not sufficiently instantiated
    

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-04-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多