Use of conditionals in Prolog

2019-09-08 05:01发布

问题:

I am confused about how conditionals are used in prolog. While Example 1 is the case for a conditional, Example 2 shows a case where it says NewPos = Exit on the other side of the -> operator. Is it checking if NewPos is equal to Exit or is it the case that the value Exit is being assigned to NewPos? Shouldn't an is be used to assign values in prolog?

Sorry if this is a very basic syntax question.

Example 1

Current = b(_,Cost,NewPos),
( Exit=none   -> backtrack_path(Current,Visited,RPath)
; Exit=b(5,5) -> backtrack_path(Current,Visited,RPath)

Example 2

Current = b(_,Cost,NewPos),
( Exit=none -> backtrack_path(Current,Visited,RPath)
; otherwise -> NewPos = Exit,
             backtrack_path(Current,Visited,RPath)

回答1:

For a more detailed look at the Prolog -> operator, see What's the meaning of Prolog operator '->'. Your examples are covered below.

Example 1:

Current = b(_,Cost,NewPos),

Unifies Current with the term, b(_, Cost, NewPos). Unficiation in Prolog is not the same as assignment. In unification, Prolog will attempt to match the two arguments of =/2 possibly instantiating variables on either side to achieve the unification. If, for example, Current, Cost and NewPos are all uninstantiated, then Current will be instantiated with b(_, Cost, NewPos) (using the same variables, Cost and NewPos. If, later on, Cost is instantiated with, say, 10, then Current will also become, b(_, 10, NewPos), in effect.

( Exit=none   -> backtrack_path(Current,Visited,RPath)
; Exit=b(5,5) -> backtrack_path(Current,Visited,RPath)

; has lower precedence than ->, so this is, in effect:

(   Exit=none
->  backtrack_path(Current,Visited,RPath)
;   (   Exit=b(5,5)
    ->  backtrack_path(Current,Visited,RPath),
        ...
    ),
    ...
)

Exit = none will attempt to unify Exit and the atom, none. It will succeed if Exit is uninstantiated (and will then instantiate Exit with none), or can succeed if Exit is already instantiated as none. It will fail if Exit is instantiated with any term that doesn't match none.

If Exit = none succeeds, then the first backtrack_path(Current, Visited, RPath) is called. If it fails, then an attempt is made to unify Exit with b(5,5). If the prior Exit = none failed, then we got to this point because Exit was already unified with something that didn't match none, and it will succeed Exit = b(5,5) only if it was already unified with a term that looks like, b(X, Y). Otherwise, it will also fail. If it succeeds, then, again, backtrack_path(Current, Visited, RPath) will be called.

Example 2:

Current = b(_,Cost,NewPos),
( Exit=none -> backtrack_path(Current,Visited,RPath)
; otherwise -> NewPos = Exit,
             backtrack_path(Current,Visited,RPath)

, has highest precedence, followed by ->, followed by ;. So this is effectively:

Current = b(_,Cost,NewPos),
(   Exit=none
->  backtrack_path(Current,Visited,RPath)
;   (   otherwise
    ->  (   NewPos = Exit,
            backtrack_path(Current,Visited,RPath),
            ...
        ),
        ...
    ),
    ...
 )

See the discussion above about unification. If Exit = none succeeds, then backtrack_path(Current, Visited, RPath) is called. Otherwise, then then otherwise call is done (NOTE that if otherwise is a block of code, then operator precedence can affect the grouping I show above, so I'm assuming otherwise is a block which has precedence over the following ->).

If otherwise succeeds, then Prolog attempts NewPos = Exit, and if that succeeds, it will move on to call, backtrack_path(Current, Visited, RPath). If the NewPos = Exit unification fails, then, in this case, lacking an "else" or "OR" (;) type of expression, it might backtrack all the way to Current = b(_, Cost, NewPos). Where it backtracks to depends completely upon what other code you have in this clause (it's a bit hypothetically presented, so it could be anything).

Regarding is/2

is/2 is used to (a) evaluate a numeric expression as its second argument, and (b) unify the result of the expression evaluation with the first argument. Here are some examples, also showing the contrast with =/2 (unification):

| ?- X = A + B.

X = A+B

yes

Here, X is unified with the term, A + B. So X is now instantiated with the term A+B (which is the term, '+'(A, B))

| ?- A = 2, B = 3, X = A + B.

A = 2
B = 3
X = 2+3

yes

X is unified with the term, A + B. A is unified with 2 (and so A is instantiated with the value 2), and B is unified with 3. So X is unified with 2+3 (or `'+'(2,3)).

| ?- A = 2, B = 3, X is A + B.

A = 2
B = 3
X = 5

yes

The expression on the right hand side of is (the second argument to is/2) is evaluated yielding 5. Then X is instantiated to 5.

| ?- A = 2, X is A + B.
uncaught exception: error(instantiation_error,(is)/2)

B isn't instantiated, so the expression, A + B cannot be evaluated, so is/2 fails due to an instantiation error.

| ?- A = 2, B = 3, Z = 5, Z is A + B.

A = 2
B = 3
Z = 5

yes

A, B, and Z are all instantiated to numeric values, and Z is A + B succeeds since A + B evaluates to 5, which is unifiable with Z which also has the value 5.

| ?- A = 2, B = 3, Z = 4, Z is A + B.

no

A, B, and Z are all instantiated to numeric values, and Z is A + B fails since A + B evaluates to 5, which is not unifiable with Z which has the value 4.

| ?- A = 2, B = 3, X = A + B, Z is X.

A = 2
B = 3
X = 2+3
Z = 5

yes

X is unified with the term, A + B, which is the term 2 + 3 since A has been instantiated with 2, and B with 3. Z is unified with the evaluation of the expression X (which is 2 + 3) and so has the value 5.



标签: syntax prolog