Variable undeclared

Viewed 47

I have a function that takes the first item from a list, and checks if that item is one of several items, executes some functions accordingly and recursively executes on the next items on the list.

My trouble is that in line 6, the variable instantiated as the first item of the list is no longer defined, and I have trouble figuring out why.

I just started working with KBSs' so forgive me if my language is incorrect.

1 f(L) :- 
2     [F|Ls] = L,
3     (
4        (F = value1 -> ...);
5        (F = value2 -> ...)
6    ) -> f(Ls); format('~w is not a valid action', [F]).

2 Answers

Example of ->/2 usage:

do_something_with_first_elem([Head|_]) :-
    do_something_with_elem(Head).
    
do_something_with_elem(Elem) :-
    ( Elem = a -> writeln('Head is a')
    ; Elem = b -> writeln('Head is b')
    ; Elem = 3 -> writeln('Head is 3 (a number)')
    ; format('~w is not a valid action', [Elem])
    ).

Result in swi-prolog:

?- do_something_with_first_elem([b, c, d]).
Head is b
true.

?- do_something_with_first_elem([z, c, d]).
z is not a valid action
true.

After compiling your code, ask the following query:

?- listing(f).

f(L) :-
    (   L=[F|Ls],                              % <== unification IS PART OF the condition!
        (   F=value1
        ->  ...
        ;   F=value2
        ->  ...
        )
    ->  f(Ls)
    ;   format('~w is not a valid action', [F]) % <== when condition fails, unification is UNDONE
    ).

As you can see, the unification is part of the condition. Thus, when condition fails, the unification is undone, turning F a single variable.

To solve the problem, format the code as follows:

f(L) :-
     [F|Ls] = L,                  % <== Now, unification IS NOT PART OF the condition!
     (   (   (F = value1 -> ...)
         ;   (F = value2 -> ...) )
     ->  f(Ls)
     ;   format('~w is not a valid action', [F]) ).
Related