2

I am writing a solution to working out distances between numbers in a list using recursion, but have been struggling with getting the intended output. I am trying to get a list of lists into a single list, but attempts at using flatten and append/2 aren't working. I have tried for hours, and keep going around in circles, can someone tell me what i'm doing wrong please?

:- use_module(library(clpfd)).

difference([],_,[]).
differwnce([L|Ls],X,[DST|Ds]) :-
   DST #= abs(X - L),
   difference(Ls,X,Ds).

differences[],[]).
differences([L|Ls], [DST|Tail]) :-
   difference(Ls,X,DST),
   differences(Ls, Tail).

Here is the intended input and output:-

?- differences([1,2,4,9],Ds).
Ds = [1,3,8,2,7,5].

Current Output:

Ds = [[1,3,8],[2,7],[5],[]].
AntMan
  • 23
  • 4
  • Please include your code in the question so we can see what you've tried – John M Apr 04 '19 at 10:41
  • 1
    Sorry, i'm a newbie to posting question on Stackoverflow and got a bit confused with the formatting. It should be up now. Thanks. – AntMan Apr 04 '19 at 10:49
  • 2
    Rolled back code you deleted because it is specific to the question. Your code used constraints in the example and thus made the answers more specific. By deleting the code beginners reading this might think that constraints are required and they are not. – Guy Coder Apr 06 '19 at 20:22
  • Does this answer your question? [Get elements from list of lists](https://stackoverflow.com/questions/9777077/get-elements-from-list-of-lists) – false Apr 24 '20 at 15:27

3 Answers3

2
seq([]) --> [].
seq([E|Es]) --> [E], seq(Es).

seqq([]) --> [].
seqq([Es|Ess]) -->
  seq(Es),
  seqq(Ess).

?- phrase(seqq([[1,3,8],[2,7],[5],[]]), Es).
   Es = [1,3,8,2,7,5].
?- dif(A,B), phrase(seqq([[A|_]|_]), [B|_]).
   false.
false
  • 10,264
  • 13
  • 101
  • 209
  • Sorry this has confused me more. I am very much a beginner to swi prolog, is there a simpler solution please? – AntMan Apr 04 '19 at 12:18
  • Hi false, do you mean set up another predicate to manually convert the list? Like append/2 usually does? Can you tell me why append/2 doesn't work in my case? – AntMan Apr 04 '19 at 12:35
1

You can convert your distances/3 predicate into a distances/4 predicate that returns a list tail for the elements that will follow, effectively using an open list:

:- use_module(library(clpfd)).

distances([], _, Tail, Tail).
distances([BN| Bs], B, [DST| Ds], Tail) :-
   DST #= abs(B - BN),
   distances(Bs, B, Ds, Tail).

triangle([], []).
triangle([BN| Bs], Ds) :-
    distances(Bs, BN, Ds, Tail),
    triangle(Bs, Tail).

Sample call:

?- triangle([1,2,4,9], Ds).
Ds = [1, 3, 8, 2, 7, 5].

To better understand this solution consider the results of the following query:

?- distances([2,4,9], 1, Ds, Tail).
Ds = [1, 3, 8| Tail].

This solution is more efficient than calling predicates such as append/2 or flatten/3 at the end.

P.S. If you still need a distances/3 predicate to use elsewhere, you can define it easily:

distances(Bs, B, Ds) :-
    distances(Bs, B, Ds, []).
Paulo Moura
  • 18,373
  • 3
  • 23
  • 33
  • Thanks a lot Paulo I will try this. My only issue is that I am restricted to have a distances/3 predicate. I could however set up another too using what you have suggested? Or is there another way I can keep distances/3? – AntMan Apr 04 '19 at 13:58
  • @AntMan You can define `distances/3` using `distances/4` easily: `distances(Bs,B,Ds) :- distances(Bs,B,Ds,[]).`. Will that work in your case? – Paulo Moura Apr 04 '19 at 14:16
  • Perfect Paulo, thanks! This has had me stuck for so many hours. I was trying to use append(ds, DST) for ages after the triangle recursive call, but it just wouldn't put it into a separate list. Do you know why that is? It's illogical lol, since append/2 is supposed to take a list of lists and concatenate into one list – AntMan Apr 04 '19 at 15:24
  • @AntMan Note that my answer is more efficient than any solution calling append or flatten predicates. – Paulo Moura Apr 04 '19 at 15:30
  • It's great. I was also trying different ways to make another List and manually put the elements in for hours yesterday, and it was just not working. Trying to understand how it works still though.. The extra Tail is taking whatever is left over from the call to distances? I'm a little confused, but great that it works – AntMan Apr 04 '19 at 15:38
1

Why not use the library predicate append/2 like so?

?- append([[1,3,8],[2,7],[5],[]], Xs).
Xs = [1,3,8,2,7,5].
repeat
  • 18,496
  • 4
  • 54
  • 166
  • @repeat i couldnt get it to work with my code, i dont know why. That was my original question – AntMan Apr 04 '19 at 19:02
  • 1
    It didnt like using Ds in append, even though its a list of lists i assume – AntMan Apr 04 '19 at 19:11
  • Use `append/2`: once at the end as a quick fix, not in the recursive clause. – repeat Apr 04 '19 at 23:57
  • It needs to be within the recursive predicate or at least call another predicate from the recursive predicate to append. I couldnt get it to work this way either though. I think i need to learn more about prolog fundamentals to understand why – AntMan Apr 06 '19 at 20:14
  • 1
    *Why not use the library predicate append/2 like so?* because append/2 produces many unnecessary errors like in `dif(A,B), append([[A|_]|_], [B|_]).` which could fail silently – false Apr 22 '19 at 20:56