Checking if the difference between consecutive ele

2019-02-28 10:00发布

问题:

I am new to using arithmetic in Prolog.

I’ve done a few small programs, but mostly involving logic. I am trying to implement a function that will return true or false if the difference between every consecutive pair of elements is the same or not.

My input would look like this: sameSeqDiffs([3, 5, 7, 9], 2) I feel like I need to split the first two elements from the list, find their difference, and add the result to a new list. Once all the elements have been processed, check if the elements of the new list are all the same.

I’ve been taught some Prolog with building relationships and querying those, but this doesn’t seem to fit in with Prolog.

Update1: This is what I've come up with so far. I am brand new to this syntax and am still getting an error on my code, but I hope it conveys the general idea of what I'm trying to do.

diff([X,Y|Rest], Result):-
    diff([Y,Z|Rest], Result2):-
       Result2 = Result,
       Z - Y = Result.

Update2: I know I still have much to do on this code, but here is where I will remain until this weekend, I have some other stuff to do. I think I understand the logic of it a bit more, and I think I need to figure out how to run the last line of the function only if there is at least two more things in the rest of the list to process.

diff([X,Y|Rest], Result):-
    number(Y),
    Y-X=Result,
    diff([Rest], Result).

Update3: I believe I have the function the way I want it to. The only quirk I noticed is that when I run and input like: sameSeqDiffs([3,5,7],2).I get true returned immediately followed by a false. Is this the correct operation or am I still missing something?

sameSeqDiffs([X,Y], Result):-
    A is Y - X,
    A = Result.

sameSeqDiffs([X,Y,Z|T], Result):-
    sameSeqDiffs([Y,Z|T], Result).

Update 4: I posted a new question about this....here is the link: Output seems to only test the very last in the list for difference function

回答1:

Prolog's syntax

The syntax is a bit off: normally a clause has a head like foo(X, Y, Z), then an arrow (:-), followed by a body. That body normally does not contain any arrows :-. So the second arrow :- makes not much sense.

Predicates and unification

Secondly in Prolog predicates have no input or output, a predicate is true or false (well it can also error, or got stuck into an infinite loop, but that is typically behavior we want to avoid). It communicates answers by unifying variables. For example a call sameSeqDiffs([3, 5, 7, 9], X). can succeed by unifying X with 2, and then the predicate - given it is implemented correctly - will return true..

Inductive definitions

In order to design a predicate, on typically first aims to come up with an inductive definition: a definition that consists out of one or more base cases, and one or more "recursive" cases (where the predicate is defined by parts of itself).

For example here we can say:

(base case) For a list of exactly two elements [X, Y], the predicate sameSeqDiffs([X, Y], D) holds, given D is the difference between Y and X.

In Prolog this will look like:

sameSeqDiffs([X, Y], D) :-
    ___.

(with the ___ to be filled in).

Now for the inductive case we can define a sameSeqDiffs/2 in terms of itself, although not with the same parameters of course. In mathematics, one sometimes defines a function f such that for example f(i) = 2×f(i-1); with for example f(0) = 1 as base. We can in a similar way define an inductive case for sameSeqDiffs/2:

(inductive case) For a list of more than two elements, all elements in the list have the same difference, given the first two elements have a difference D, and in the list of elements except the first element, all elements have that difference D as well.

In Prolog this will look like:

sameSeqDiffs([X, Y, Z|T], D) :-
    ___,
    sameSeqDiffs(___, ___).

Arithmetic in Prolog

A common mistake people who start programming in Prolog make is they think that, like it is common in many programming languages, Prolog add semantics to certain functors.

For example one can think that A - 1 will decrement A. For Prolog this is however just -(A, 1), it is not minus, or anything else, just a functor. As a result Prolog will not evaluate such expressions. So if you write X = A - 1, then X is just X = -(A,1).

Then how can we perform numerical operations? Prolog systems have a predicate is/2, that evaluates the right hand side by attaching semantics to the right hand side. So the is/2 predicate will interpret this (+)/2, (-)/2, etc. functors ((+)/2 as plus, (-)/2 as minus, etc.).

So we can evaluate an expression like:

A = 4, is(X, A - 1).

and then X will be set to 3, not 4-1. Prolog also allows to write the is infix, like:

A = 4, X is A - 1.

Here you will need this to calculate the difference between two elements.



回答2:

You were very close with your second attempt. It should have been

samediffs( [X,  Y | Rest], Result):-
    Result is Y - X,
    samediffs( [Y | Rest], Result).

And you don't even need "to split the first two elements from the list". This will take care of itself.

How? Simple: calling samediffs( List, D), on the first entry into the predicate, the not yet instantiated D = Result will be instantiated to the calculated difference between the second and the first element in the list by the call Result is Y - X.

On each subsequent entry into the predicate, which is to say, for each subsequent pair of elements X, Y in the list, the call Result is Y - X will calculate the difference for that pair, and will check the numerical equality for it and Result which at this point holds the previously calculated value.

In case they aren't equal, the predicate will fail.

In case they are, the recursion will continue.

The only thing missing is the base case for this recursion:

samediffs( [_], _Result).  
samediffs( [], _Result).

In case it was a singleton (or even empty) list all along, this will leave the differences argument _Result uninstantiated. It can be interpreted as a checking predicate, in such a case. There's certainly no unequal differences between elements in a singleton (or even more so, empty) list.


In general, ......

recursion(A, B):- base_case( A, B).

recursion(  Thing,  NewThing):-
  combined( Thing,             Shell, Core),
  recursion(                          Core, NewCore),
  combined(         NewThing,  Shell,       NewCore).

...... Recursion!



标签: list prolog