Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

how does this query work

15 views
Skip to first unread message

Joe

unread,
Sep 11, 2016, 12:34:56 AM9/11/16
to
The problem is the following web query returns all parts for a specific
model. I am trying to make it such that, if I ask for model, major, and
minor, then only a single part will be returned.

page_content(_Request) -->
html(
[
form([action='/search', method='POST'], [
p([], [
label([for=model], 'Model '),
input([name=model, type=textarea])
]),
p([], [
label([for=major], 'Major '),
input([name=major, type=textarea])
]),
p([], [
label([for=minor], 'Minor '),
input([name=minor, type=textarea])
]),
p([], input([name=submit, type=submit, value='Search'], []))
])]).

I think I understand memberchk, findall, and maplist individually, but I
don't understand how this queries the facts below in the parts file.
Could someone briefly explain this so that I can understand it and make
the needed changes.

query_verse(Request) :-
member(method(post), Request), !,
http_read_data(Request, Data, []),
format('Content-type: text/html~n~n', []),
format('<p>', []),
memberchk(model=Model, Data),
findall(p(Model, Major, Minor, Desc),
part(Model, Major, Minor, Desc), Descriptions),
maplist(desc, Descriptions),
format('</p>').

desc(p(M,A,I,D)) :- format("~q ~q:~q - ~q</br>", [M,A.I.D]).

This is my parts.pl file.

:- module(parts,[part/4]).
% part(model, major, minor, description).
part(jeep, 100, 1000, 'description of 100-1000').
part(jeep, 100, 1001, 'description of 100-1001').
part(jeep, 100, 1002, 'description of 100-1002').
part(jeep, 101, 1000, 'description of 101-1000').
part(jeep, 101, 1001, 'description of 101-1001').
part(jeep, 101, 1002, 'description of 101-1002').
part(ford, 101, 1000, 'description of 101-1000').

Markus Triska

unread,
Sep 11, 2016, 1:10:11 PM9/11/16
to
Joe <no....@noemail.com> writes:

> I think I understand memberchk, findall, and maplist individually, but I
> don't understand how this queries the facts below in the parts file.
> Could someone briefly explain this so that I can understand it and make
> the needed changes.
>
> query_verse(Request) :-
> member(method(post), Request), !,
> http_read_data(Request, Data, []),
> format('Content-type: text/html~n~n', []),
> format('<p>', []),
> memberchk(model=Model, Data),
> findall(p(Model, Major, Minor, Desc),
> part(Model, Major, Minor, Desc), Descriptions),

The key idea of this findall/3 is to find all solutions of the query:

?- part(Model, Major, Minor, Desc).

However, instead of yielding all solutions on backtracking (as this
query wold), findall/3 collects them in "spatial" form in the list
Descriptions as terms of the form p(Model,Major,Minor,Desc).

Try it yourself:

?- findall(p(Model,Major,Minor,D), part(Model,Major,Minor,D), Ds).
%@ Ds = [p(jeep, 100, 1000, 'description of 100-1000'), ...].

Your example implements one part of the search by instantiating Model
according to the attribute value that is specified in Data:

memberchk(model=Model, Data),

Since Model is already instantiated, only matching solutions are found.

Again, try it yourself on the toplevel, with Model instantiated:

?- Model = ford,
findall(p(Model,Major,Minor,D), part(Model,Major,Minor,D), Ds).
%@ Model = ford,
%@ Ds = [p(ford, 101, 1000, 'description of 101-1000')].

So you see that the single ford model is found if you specify
Model=ford.

All it takes to complete this is for you to instantiate also the other
attributes according to the values that are specified in the request:

memberchk(major=Major, Data),
memberchk(minor=Minor, Data),
etc.

so that you have Major and Minor etc. also instantiated.

Watch out for the difference between atoms and numbers when processing
these requests! For example, the following does not yield any solutions:

?- part(_, '100', _, _).
%@ false.

but the following does:

?- part(_, 100, _, _).
%@ true .

All the best,
Markus

--
comp.lang.prolog FAQ: http://www.logic.at/prolog/faq/

Joe

unread,
Sep 11, 2016, 4:28:19 PM9/11/16
to
Thanks for you explanation. It helped immensely.

I misunderstood the instantiation and saw it just as a check in memberchk.

And now I see what you mean about the difference between atoms and
numbers. If I change my parts file to use '100' instead of 100, then it
all works. So I have the following questions if I may.

Is it better to use atoms or numbers? I used the numbers because they
map exactly to the items I was trying to track. So other than for
identification purposes, is there a reason I should use one or the other?

Markus Triska

unread,
Sep 11, 2016, 5:20:39 PM9/11/16
to
Joe <no....@noemail.com> writes:

> Is it better to use atoms or numbers? I used the numbers because they
> map exactly to the items I was trying to track. So other than for
> identification purposes, is there a reason I should use one or the
> other?

You should use the representation that matches the actual character of
your data, so that you can represent your data without loss and at the
same time allow all pertinent Prolog operations on it. For example, if
you use integers, you can very naturally ask for greater integers,
variants within a certain range or at least two versions apart etc.

In this specific case, storing the numbers as Prolog integers seems
preferable so far, if that is "what they are". But as soon as you have
for example major models "X" and "Z", integers will no longer fit this.

Note that you can also dynamically convert atoms to numbers before you
do the actual query, so you can still use numbers in your fact base even
though you obtain atoms from the HTML form:

?- atom_number('123', I).
%@ I = 123.

This of course also goes the other way:

?- atom_number(A, 123).
%@ A = '123'.

Eventually, you will probably also implement regexp or pattern-based
searches over your data, and in such cases you will likely need such
dynamic conversion predicates between different representations.
0 new messages