As far as I know, Prolog does not have any built-in mechanisms for generic programming. It's possible to simulate generics using unification, but this requires type-checking at runtime:
:- 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).
Is it possible to write "generic" predicates without checking the type of each variable at runtime?
Some forms of generic programming are available in Prolog via Logtalk, which extends Prolog and can be used with most Prolog systems.
Given that you want different definitions of the add/3
predicate to be used depending on the type of the first two arguments, we can start by defining a protocol declaring the predicate:
:- protocol(math_protocol).
:- public(add/3).
:- end_protocol.
Based in your sample code, we can now define different implementations for the predicate:
:- 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.
We can modify the number
and var
objects to also perform the type-checking. for example:
:- object(number,
implements(math_protocol)).
add(A, B, C) :-
number(A),
number(B),
C is A + B.
:- end_object.
In alternative, we can define an object parametric on the type that performs the type-checking and then delegates the actual operation on the type. For example:
:- object(math(_Type_),
implements(math_protocol)).
add(A, B, C) :-
call(_Type_, A),
call(_Type_, B),
_Type_::add(A, B, C).
:- end_object.
A sample call in this case would be:
?- math(number)::add(2, 3, Sum).
Sum = 5
yes
But note that these alternatives will still be performing type-checking at runtime.
The parametric object can be modified to find the type of the arguments as in your sample code. But that's quite inefficient without a built-in Prolog predicate that allows querying a term type (no standard for it and also not available in general, however).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With