claire
claire

Reputation: 39

Iterating List in Prolog

I would like to iterate a list in Prolog an write a generated result into a new list. With the predicate next_level_segments(List of Start-, Endcoordinates) I would like to calculate four lists of four coordinates between each pair of Start-, and Endcoordinates and store this four lists in Ls. This means when I call for example

next_level_segments([
                       [(10,0),(3.3,0)],
                       [(3.3,0),(0,-5.8)],
                       [(0,-5.8),(-3.3,0)],
                       [(-3.3,0),(-10,0)]
                     ])

the predicate segments() should calculate the four next coordinates between the pair of Start- and Endcoordinates for example [(10,0),(3.3,0)]. So next_level_segments should iterate through the list of Start and Endpoints, segments should do the calculation and the result of four list, with each four pairs of coordinates should be stored in the a resulting list.

When I call next_level_segments() with a list of four coordinates, the calculation is done and the coordinates are generated when i look at the trace, but aren't stored correctly. As far as I can see it in the trace, the last list of four coordinates is missing. Maybe somebody may have a look and have some advice what I'm doing wrong.

Thank you

segments([(Sx,Sy),(Ex,Ey)],Ls):-
    X2 is Sx+(Ex-Sx)/3,
    Y2 is Sy+(Ey-Sy)/3,
    R1 is sqrt((X2-Sx)*(X2-Sx)+(Y2-Ey)*(Y2-Ey)),
    Phi1 is atan((Y2-Sy)/(X2-Sx)),
    X3 is X2 +R1*cos((Phi1-240)*pi/180),
    Y3 is Y2 +R1*sin((Phi1+240)*pi/180),
    X4 is X2+(X2-Sx),
    Y4 is Y2+(Y2-Sy),
         Ls=[
             [(Sx,Sy),(X2,Y2)],
             [(X2,Y2),(X3,Y3)],
             [(X3,Y3),(X4,Y4)],
             [(X4,Y4),(Ex,Ey)]].    

next_level_segments([[(Sx,Sy),(Ex,Ey)]|E],[X|RLs]):-
    segments([(Sx,Sy),(Ex,Ey)],X),
    next_level_segments(E,RLs). 

next_level_segments([],[]).

Upvotes: 0

Views: 289

Answers (1)

user1812457
user1812457

Reputation:

Your next_level_segments/2 needs only two clauses (instead of the three you are using). The first one should be:

next_level_segments([], []).

Both the first and the third clause you have at the moment should go because they don't do anything useful.

The recursive clause seems fine as it is at the moment.

Corrected like this, I get:

?- next_level_segments(
       [[(10,0),(3.3,0)],
        [(3.3,0),(0,-5.8)],
        [(0,-5.8),(-3.3,0)],
        [(-3.3,0),(-10,0)]
       ],
       X).
X = [[[(10, 0),  (7.766666666666667, 0)], [(7.766666666666667, 0),  (6.649999999999999, -1.9341234017852458)], [(6.649999999999999, -1.9341234017852458),  (5.533333333333333, 0)], [(5.533333333333333, 0),  (3.3, 0)]],
     [[(3.3, 0),  (2.2, -1.9333333333333333)], [(2.2, -1.9333333333333333),  (0.1262841490828066, -5.451200543142186)], [(0.1262841490828066, -5.451200543142186),  (1.1000000000000005, -3.8666666666666667)], [(1.1000000000000005, -3.8666666666666667),  (0, -5.8)]],
     [[(0, -5.8),  (-1.0999999999999999, -3.8666666666666663)], [(-1.0999999999999999, -3.8666666666666663),  (-3.0456930398351094, -7.310619872034865)], [(-3.0456930398351094, -7.310619872034865),  (-2.1999999999999997, -1.9333333333333327)], [(-2.1999999999999997, -1.9333333333333327),  (-3.3, 0)]],
     [[(-3.3, 0),  (-5.533333333333333, 0)], [(-5.533333333333333, 0),  (-6.65, -1.9341234017852458)], [(-6.65, -1.9341234017852458),  (-7.766666666666667, 0)], [(-7.766666666666667, 0),  (-10, 0)]]
    ].

Keep in mind that a trivial list iteration like this can also be written simply as:

maplist(segments, Input, Output)

In other words, apply segments/2 to each corresponding element in the two lists. You would have to redefine your segments/3 however to have two arguments instead of three, for example by re-writing the head to:

segments([(Sx,Sy),(Ex,Ey)], Ls)

(put the two first arguments in a list, as they are in your input list)

A small comment: a pair in Prolog is usually written as X-Y, not as (X, Y). Many standard library predicates represent "pairs" as X-Y, for example keysort/2, library(pairs) and so on. If you want to, you could also give your pair a descriptive name like pair(X,Y) or coordinates(X,Y). It doesn't really matter of only two elements, but a "tuple" with three elements like this: (X,Y,Z) is actually a nested term:

?- write_canonical((X,Y,Z)).
','(_,','(_,_))
true.

You get the same problem with X-Y-Z:

?- write_canonical(X-Y-Z).
-(-(_,_),_)
true.

At that point you could again use a term with a descriptive name, for example triple(X, Y, Z) or coordinates(X, Y, Z).

Upvotes: 4

Related Questions