Here is a solution where you still have to write a bit of code for each operator you want to handle, but which still provides nice syntax at the point of use.
Let's start with a notion of evaluating an arithmetic expression on vectors to a vector. This essentially applies arithmetic operations component-wise. (But you could add a dot product or whatever you like.)
:- use_module(library(clpr)).
vectorexpr_value((X,Y,Z), (X,Y,Z)).
vectorexpr_value(V * T, (X,Y,Z)) :-
vectorexpr_value(V, (XV,YV,ZV)),
{ X = XV * T },
{ Y = YV * T },
{ Z = ZV * T }.
vectorexpr_value(L + R, (X,Y,Z)) :-
vectorexpr_value(L, (XL,YL,ZL)),
vectorexpr_value(R, (XR,YR,ZR)),
{ X = XL + XR },
{ Y = YL + YR },
{ Z = ZL + ZR }.
vectorexpr_value(L - R, (X,Y,Z)) :-
vectorexpr_value(L, (XL,YL,ZL)),
vectorexpr_value(R, (XR,YR,ZR)),
{ X = XL - XR },
{ Y = YL - YR },
{ Z = ZL - ZR }.
So for example:
?- vectorexpr_value(A + B, Result).
A = (_1784, _1790, _1792),
B = (_1808, _1814, _1816),
Result = (_1832, _1838, _1840),
{_1808=_1832-_1784},
{_1814=_1838-_1790},
{_1816=_1840-_1792} .
Given this, we can now define "equality" of vector expressions by "evaluating" both of them and asserting pointwise equality on the results. To make this look nice, we can define an operator for it:
:- op(700, xfx, ===).
This defines ===
as an infix operator with the same priority as the other equality operators =
, =:=
, etc. Prolog doesn't allow you to overload operators, so we made up a new one. You can think of the three =
signs in the operator as expressing equality in three dimensions.
Here is the corresponding predicate definition:
ExprL === ExprR :-
vectorexpr_value(ExprL, (XL,YL,ZL)),
vectorexpr_value(ExprR, (XR,YR,ZR)),
{ XL = XR },
{ YL = YR },
{ ZL = ZR }.
And we can now define line/4
almost as you wanted:
line(P1, P2, T, P3) :-
(P2 - P1) * T === P3.
Tests:
?- line((0,0,0), (1,1,1), Alpha, (2,2,2)).
Alpha = 2.0 ;
false.
?- line((0,0,0), (1,1,1), Alpha, (2,3,4)).
false.