Search code examples
databasevariablesprologassignrule

How can I assign multiple values to a variable (like a string) in Prolog?


Earlier today I asked for help for building a database in prolog and how to search by parameters, and somebody came up with this:

You can also add a list of terms to every processor, like:

processor(pentium_g4400, [brand('intel'),    family('pentium'),
                          series('g4400'),   clock(3.3),
                          socket('lga1151'), ram('ddr4'),
                          cores(2),          threads(2)]).

In that case you can query with:

processor(Proc, Specs), member(family('pentium'), Specs).

And it worked pretty well, but, the command "member" does not seem to work with a rule:

build(ProcSpecs, RamSpecs, MoboSpecs):-
        processor(NameProc, PSpec), member(ProcSpecs, PSpec),
        component_ram(NameRam, RSpec), member(RamSpecs, RSpec),
        motherboard(NameMobo, MSpec), member(MoboSpecs, MSpec),
        write("-----------------------------"), nl, 
        write("Processor: "), write(NomeProc), nl,
        write("Ram: "), write(NomeRam), nl,
        write("Motherboard: "), write(NomeMobo), nl.

If I query like this:

build(ram(ddr4), ram(ddr4), ram(ddr4)).

(Or putting any other parameters I would like to search) It answer me a list of components that match the parameter (which is the result I'm looking for). But, if I try to use "member" to set more than one parameter, like this:

build(ProcSpecs, RamSpecs, MoboSpecs), member(socket('lga1151'), ProcSpecs), member(ram('ddr4'), ProcSpecs), member(ram('ddr41'), RamSpecs), member(socket('lga1151'), MoboSpecs), member(ram('ddr4'), MoboSpecs).

It starts listing every component on the database, and it seems like it happens because nothing is being assigned to the variable. The whole database is here: https://pastebin.com/1Yy6cTV9


Solution

  • Looking at your database file, I think the advice you got earlier today wasn't the right direction. I would probably handle this as a straight relational database, with a table like this:

    % processor(Id, Brand, Family, Series, Clock, Socket, RAM, Cores, Threads).
    

    Then I would recast the DB you made like so:

    processor(pentium_g4400, intel, pentium, g4400, 3.3, lga1151, ddr4, 2, 2).
    

    This is what you'd do with a relational database and I think it's what you should do here as well. Now if you want to query on just one aspect, you do it positionally:

    ?- processor(Processor, _, pentium, _, _, _, _, _, _).
    Processor = pentium_g4400 ;
    ...
    

    Then you'd do the same thing with your two other relations:

    component_ram(corsair_dominator_platinum_8gb_ddr4, corsair, dominator, platinum, '8gb', ddr4).
    motherboard(asus_prime_z270m-plus, asus, prime_z270m-plus, z270, lga1151, 4, ddr4).
    

    Now doing a "join" is done simply by using the same variable in two places:

    ?- processor(Processor, _, _, _, _, Socket_type, RAM_type, _, _),
       component_ram(RAM, _, _, _, _, RAM_type),
       motherboard(Motherboard, _, _, _, Socket_type, _, RAM_type).
    

    This produces the 3-way join. And you can use more variables to obtain more information from the three records you obtain:

    Processor = pentium_g4400,
    Socket_type = lga1151,
    RAM_type = ddr4,
    RAM = corsair_dominator_platinum_8gb_ddr4,
    Motherboard = asus_prime_z270m-plus.