0

I'd like to implement some kind of "databases" in Prolog.

I've two ideas to model tables and row :

% First one
client('B069','Laurent','769, rue de la LALALA','LLN','A1',10000).

% Second one
data(client,'B069',name,'Laurent').
data(client,'B069',adress,'69, rue de la LALALA').
data(client,'B069',town,'LLN').
data(client,'B069',cat,'A1').
data(client,'B069',amount,10000).

With the two models I can for example make respectively a "SELECT ID FROM client WHERE amount > 0" for client with positive amount :

% First one
client1_positive(Client) :- findall(ID,(data(client,ID,compte,Amount),Amount>0),Client).

% Second one
client2_positive(Client) :- findall(ID,(client(ID,_,_,_,_,Amount),Amount>0),Client).

They both have the same output ;

?- client1_positive(Clients).
Client = ['B069'].

?- client2_positive(Clients).
Client = ['B069'].

But here is my problem, since I'm very new to Prolog I have absolutely no idea how I can make that dynamic, like "SELECT name FROM client WHERE ID = 'B069' ". I can implement a rule for this specific SQL query but I can't find a way to implement a more abstract rule so every query could be interpreted.

Is there a best pratice for how to model those kind of datas in Prolog ? And some ideas (not a detailed answer to my problem) on how to make a request more abstract in Prolog ?

Thanks a lot

1
  • there is no need to use findall prematurely. just rely on non-determinism/backtracking and do findall (or bagof or setof) as late as possible. this way your predicates/rules will compose automatically. findall is kind of like an early forced evaluation of a computation that is normally lazily backtracked. Commented Feb 9, 2022 at 10:33

2 Answers 2

2

Think about how you would do this with a relational database. You would probably have a Client table with records consisting of client id (key), client name, address, phone, other contact info. You wouldn't want a separate record for name, address, phone, etc. That would be too cumbersome.

You would have separate tables for client data that have some relationship with the client (one-to-one, many-to-one, many-to-many, ...). If a client were to possibly have more than one set of contact information, then that's a many-to-one relationship between contact information and client, so you'd set up a separate ContactInfo table with a "contact_info_id" as primary key and it would have records with contents contact_info_id, client id, contact information. In the case of the amounts in your example, you would have an Amount table with records that consist of amount id (key), client id, amount.

To do this in Prolog, you'd structure it basically the same way. Setup up client data and amount data:

% clients
client('B069', 'John Doe', '123 Main St', 123-456-1234).
client('B070', 'Jane Smith', '100 West Elm', 999-999-8888).
...

% amounts
amount('A010', 'B069', 10000).
amount('A010', 'B070', 10100).
...

The above could be one-to-one or many-to-one.

The equivalent of the query: SELECT name FROM client WHERE ID = 'B069' would be:

?- client('B069', Name, Address, Phone).

Your selection of positive amounts would be:

client_positive(Clients) :-
    findall(ClientId, (amount(_, ClientId, Amount), Amount > 0), Clients).
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks that helped me. And do you know with that model how I can get for exemple the second argument in client, a rule like nth_arg(+Predicate,+Nth,-Argument). Does that sort of rule exists ?
@tomatediabolik in this case, you know the meaning of each argument position. What's the use case for picking out the argument by index? Normally, you might have something like, client_phone(ClientId, Phone) :- client(CllientId, _, _, Phone). or something like that. If you really do need to pick it out by index, you can use arg/3 (arg(+Nth, +Term, -Argument)) which will obtain the nth argument of a term. Without more info on your use case, I'm not sure what more to say about it.
0

Your first approach is fine. You might need the second if, for example, a person can have more than one adress.

A query is just a term with variables:

| ?- client('B069',Name,Adress,Town,Cat,Amount).
Cat = 'A1',
Name = 'Laurent',
Town = 'LLN',
Adress = '769, rue de la LALALA',
Amount = 10000 ?

You can use any of the parameters as the key in the query. Your Prolog may not index on all of them, which may or may not be an issue.

| ?- client(Key,'Laurent',_,_,_,_).
Key = 'B069' ? 

If there are multiple answers, then they are returned via backtracking. Findall collects them together in a list, which may or may not be what you want.

If by "dynamic" you meant adding and removing content from the database, then you can assert/1 and retract/1.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.