Ionut
Ionut

Reputation: 1749

Prolog: Different behaviour of single and double quotes

I'm quite new to Prolog and I stumbled on something that I don't understand.

This is my code:

:- dynamic user/3.
user('id', 'Name', 20).

changeAge(Id, NewAge) :-
   user(Id, Name, _),
   retract(user(Id,_,_)),
   assert(user(Id,Name,NewAge)).

To update user information in the database, changeAge/2 performs these three steps:

  1. Lookup a right record, using user/3.
  2. Remove one matching record from the database, using retract/1.
  3. Insert a new updated record into the database, using assert/1.

This is my console output:

1 ?- user('id', _, Age).
Age = 20.

2 ?- changeAge('id', 25).
true.

3 ?- user('id', _, Age).
Age = 25.

4 ?- changeAge("id", 30).
false.

5 ?- user('id', _, Age).
Age = 25.

Why do single quotes give me true (line 2) when double quotes give me false (line 4)?

Upvotes: 4

Views: 424

Answers (2)

repeat
repeat

Reputation: 18726

TL;DR1: Read this answer to the question "What is the difference between ' and " in Prolog?".

TL;DR2: The goal 'id' = "id" succeeds iff the Prolog flag double_quotes is set to atom.

The Prolog flag double_quotes can be set at runtime using set_prolog_flag/2:

  • ?- set_prolog_flag(double_quotes, chars).

    ?- 'id' = "id".
    false.
    
  • ?- set_prolog_flag(double_quotes, codes).

    ?- 'id' = "id".
    false.
    
  • ?- set_prolog_flag(double_quotes, atom).

    ?- 'id' = "id".
    true.
    

For more information read the SICStus Prolog manual page on "Strings as lists"!

Upvotes: 6

repeat
repeat

Reputation: 18726

Let's say some users got multiple records for the same ID in the database; something that might have potential uses, say, if people may have more than one name... either way, this answer is not about getting the modeling part right, but about the technical aspects of ! YMMV.

:- dynamic(user/3).

init_db :-
   retractall(user(_,_,_)),
   maplist(assert, [user(i,n,1),user(i,n,2),user(i,m,1),user(i,m,2),
                    user(j,n,1),user(j,n,2),user(j,m,1),user(j,m,2)]).

changeAge(Id, NewAge) :-
   user(Id, Name, _),
   retract(user(Id,_,_)),
   assert(user(Id,Name,NewAge)).

Let's initialize the database and "change some ages" :-)

?- init_db, (changeAge(i,6) ; changeAge(j,7)), false.
false.

?- findall(user(Id,Name,Age), user(Id,Name,Age), DB).
DB = [user(i,m,6),user(i,m,6),user(i,m,6),user(i,m,6),
      user(j,m,7),user(j,m,7),user(j,m,7),user(j,m,7)].

Bad! in: 8 distinct records. out: 2 distinct records, each one having a multiplicity of 4.

Let's restore with above original facts and then use changeAge/2 slightly differently:

?- init_db, changeAge(_,_), false.
false.

?- findall(user(Id,Name,Age), user(Id,Name,Age), DB).
DB = [user(i,m,_),user(i,m,_),user(i,m,_),user(i,m,_),
      user(j,m,_),user(j,m,_),user(j,m,_),user(j,m,_)].

Even worse! in: 8 distinct ground records. out: 2 distinct non-ground records.

Bottom line: Be mindful of the "handle with care" warning sign attached to !

Upvotes: 2

Related Questions