开发者

Prolog: Decrementing variable in argument

I am new to Prolog and was tasked with a Fibonnaci predicate fib( N, F) where N is the number in sequence, and F is the value. What I came up with does not work, but the solution I found seems identical to me... I cannot understand the difference.

My version:

/* MY VERSION, DOES NOT WORK */
fib( 0, 0).
fib( 1, 1).
fib(N,F) :-
    N > 1,
    fib(N-1,F1),
    fib(N-2,F2),
    plus(F1,F2,F).

The working version:

/* FOUND SOLUTION, DOES WORK */
fib( 0, 0).
fib( 1, 1).
fib(N,F) :-
    N > 1,
    N1 is N-1,
    N2 is N-2,
    fib(N1,F1),
    fib(N2,F2),
    plus(F1,F2,F).

Obviously the problem has something to do with me using "N-1" and "N-2" as arguments rather than assigning those values to new variables first. But I don't get it... because in other recursive Prolog codes, I have successfully done just that (decremented a variable right in the argument slot). Does this make sense?

Thanks!


Below is an example where the "N-1" did work.

line( N, _, _) :-
    N =:= 0.

line( N, M, Char) :-
    N > 0,
    N mod M =\= 1,
    write( Char), 开发者_StackOverflowwrite( ' '),
    line( N-1, M, Char).

line( N, M, Char) :-
    N > 0,
    N mod M =:= 1,
    write( Char), write( '\n'),
    line( N-1, M, Char).

square( N, Char) :-
    N > 0,
    line( N*N, N, Char).

A new version of fib/2 which also works!

/* NEW VERSION, CHANGED TRIVIAL CASES TO EVALUATE N */
fib( N, 0) :-
    N =:= 0.

fib( N, 1).
    N =:= 1.

fib(N,F) :-
    N > 1,
    fib(N-1,F1),
    fib(N-2,F2),
    plus(F1,F2,F).


In prolog,

1 - 2

Doesn't actually do any arithmetic (I know, right?), it creates a structure:

-(1, 2)

And is is a predicate that evaluates that structure:

is(X, -(1, 2))

Will unify X with -1.

Also apparently < and > (and those like it) are like is in that they evaluate expressions.

So that means that the difference between your fib predicate and your line predicate is that

fib(0, 0).

is using unification, ie, testing whether the terms themselves are equal:

foo(0).

?- foo(1 - 1).
false

Whereas a test like =:= tests for numerical equality:

foo(X) :- X =:= 0.

?- foo(1 - 1).
yes


I'd probably write the predicate somthing like the following.

fib/2 is the outer 'public' interface. N is the position in the sequence (zero-relative). F gets unified with the value of the Fibonacci sequence at that position.

fibonacci/5 is the inner 'core' that does the work.

  • The 1st argument is the counter
  • The 2nd argument is the limit
  • The 3rd/4th arguments are the sliding frame required to compute the next item in the sequence. It should be noted that there is not required for a Fibonacci sequence start start with { 1 , 1 }. Any two integers will do.
  • The 5th argument gets unified with the desired result.

Each clause in the core works as follows:

  • If N is 0, F is unified with '1'.
  • If N is 1, F is unified with '1'.
  • If the limit has been reached, we're done. Unify F with the sum of the preceding two elements in the sequence.
  • If counter is less than the limit, compute the next element in the sequence and recurse, sliding the oldest value out from the sliding window.

Here's the code:

fib( N , F ) :-
  N >= 0 ,
  fibonnaci( 0 , N , 1 , 1 , F ).

fibonacci( 0     , 0     , F , _ , F ).
fibonacci( 1     , 1     , _ , F , F ).
fibonacci( Limit , Limit , X , Y , F ) :-
  F is X + Y
  .
fibonacci( Current , Limit , X , Y , F ) :-
  Current < Limit ,
  Next is Current + 1 ,
  Z is X + Y ,
  fibonacci( Next , Limit , Y , Z , F )
  .
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜