Search code examples
prologinstantiation-error

Prolog sum distance between list of nodes ids


node(1,22,44).
node(2,43,53).
node(3,23,12).

distance(Id1,Id2,D) :-
    node(Id1,X1,Y1),
    node(Id2,X2,Y2),
    D is sqrt((X2-X1)^2 + (Y2-Y1)^2).

distancePath([X,Y],D) :-
    distance(X,Y,D).
distancePath([H,X|T],Distance) :-
    distancePath([X|T],Rest),
    distance(H,X,D),
    Aux is Rest + D,
    Distance is Distance + Aux.

I have some kind of problem on the distancePath because when i run distancePath([1,2,3],Distance). it give me "Instantiation error in argument 2 of (is)/2" can someone help me?


Solution

  • Distance is Distance + Aux. does not make much sense. Variables are immutable, this means once set the variable will keep the same value in that branch of the Prolog evaluation. Furthermore Distance is unbounded, hence the error.

    You actually already have the value for Distance: it is Aux since it is the distance for the Rest of the list, plus the distance D:

    distancePath([X,Y], D) :-
        distance(X,Y,D).
    
    distancePath([H,X|T], Aug) :-
        distancePath([X|T],Rest),
        distance(H,X,D),
        Aux is Rest + D.

    This then gives us:

    ?- distancePath([1,2,3], D).
    D = 68.4652982294199 ;
    false.
    

    The above is however not very efficient: it does not make use of tail recursion, and furthermore you perform unpacking of the cons constructor multiple times. You can make use of a helper predicate to boost efficiency:

    distancePath([X|T], Result) :-
        distancePath(T, X, 0, Result).
    
    distancePath([], _, D, D).
    distancePath([J|T], I, Di, Do) :-
        distance(I, J, Dd),
        D2 is Di + Dd,
        distancePath(T, J, D2, Do).