prologinstantiation-error

uncaught exception: error(instantiation_error,(is)/2)


I'm making a program that recognize if in a string there are only letters and spaces, but it gives me an error and I can't solve it.

uncaught exception: error(instantiation_error,(is)/2)

i think the error stays in validazione_lista but i can't solve it.

validazione_input(Input) :-
repeat,
    read(Input),
    validazione_lista(Input, A),
(   A == 0 -> write('\ninput non valido, inserire solamente lettere maiuscole, minuscole e spazi:'), nl, fail
;   A == 1 -> !
).

validazione_lista([], _).
    validazione_lista([TESTA|CODA], A) :-
    validazione_lettera(TESTA, B),
    if_validazione(B, (validazione_lista(CODA, C), A is C), A is B).

validazione_lettera(Lettera, A) :-
    Lettera == 32,
    A is 1,
    !.
validazione_lettera(Lettera, A) :-
    (Lettera >= 65, Lettera =< 90),
    A is 1,
    !.  
validazione_lettera(Lettera, A) :-
    (Lettera >= 97, Lettera =< 122),
    A is 1,
    !.
validazione_lettera(_, A) :-
    A is 0.

if_validazione(C, I1, _) :- C=1, !, I1.
if_validazione(C, _, I2) :- C=0, !, I2.

Solution

  • This line is the problem:

    validazione_lista([], _).
    

    It does not say whether an empty list is valid or invalid, it lets an empty list be undecided. Now the code

    (validazione_lista(CODA, C), A is C)
    

    has an unknown A and unknown C and does _ is _ which gives the error. Change it to

    validazione_lista([], 1).
    

    so an empty list is valid input, and the code works.


    NB. encoding all the truth/false information in Prolog variables and writing your own if/else is not needed, and makes the code harder to follow. e.g.

    validazione_lettera(Lettera, A) :-
        Lettera == 32,
        A is 1,
        !.
    

    "a letter is valid if that letter is a space and A is 1" can be written:

    validazione_lettera(Lettera) :-
        Lettera == 32,
        !.
    

    "a letter is valid if that letter is a space". That simplifies to:

    validazione_lettera(32).
    

    "32 is a valid letter code". You don't need "other codes are invalid", that happens by default.

    All the code simplifies like this. validazione_lista([]). says an empty list is valid. Then the main list check simplifies to "a list is valid if the first item is valid and the rest is valid", two short lines:

    validazione_lista([]).
    validazione_lista([TESTA|CODA]) :-
        validazione_lettera(TESTA),
        validazione_lista(CODA).
    

    Then you can remove if_validazione completely. You can make the main loop test directly:

    (   validazione_lista(Input) -> true 
    ;  write('\ninput non valido, inserire solamente lettere maiuscole, minuscole e spazi:'), nl, fail
    ).
    

    Then you can remove A, B, C all through the code, remove A is B and A is C. Maybe use between(65, 90, Lettera). as well.