How to merge lists in PROLOG? - prolog

I need to merge two lists L1=[1,2,3] and L2=[a,b] like this: M=[1,a,2,b,3].
How can I do it in PROLOG please?

you can try
m2([A|As], [B|Bs], [A,B|Rs]) :-
!, m2(As, Bs, Rs).
m2([], Bs, Bs) :- !.
m2(As, [], As).

You may look at this link: Prolog program to merge two ordered lists
This will not give you the output you need, but it is a start.
After some tries, here is the correct answer, much simple than the original proposed by me (tested and working).
mergelist_alternate([],[],[]).
mergelist_alternate([X],[],[X]).
mergelist_alternate([],[Y],[Y]).
mergelist_alternate([X|List1],[Y|List2],[X,Y|List]) :- mergelist_alternate(List1,List2,List).
You can call it like this:
mergelist_alternate([1,2,3],[a,b],L),!.

merge_list([],L,L ).
merge_list([H|T],L,[H|M]):-
merge_list(T,L,M).
It will work. 100% tested!
Input: merge_list([1,2],[3,4],M).
Output: M=[1,2,3,4].

Related

What do these predicates do in Prolog

I don't understand what exactly these following 4 predicates do:
predicate1([H1,H2|T1],X) :−
append([H1,H2|T1],[H2,H1|T1],X).
predicate2wrapper(In, Out) :-
predicate2([ ], In, Out).
predicate2(L, [ ], L).
predicate2(A,[H| T], Out) :-
predicate2([H,H|A],T, Out).
predicate3([X,X], [X,X|_]).
predicate3([X,X], [_,H|T]) :−
predicate3([X,X],[H|T]).
predicate4([ ], _) .
predicate4([H|T], L) :−
member(H,L),
predicate4(T,L).
I know that all these predicates take lists as their argument(s) and I also tried to run them but I always get a Syntax error: operator expected warning.
Could someone please help me understand what these predicates do and maybe also help me fix this error?
Did you copy this from a pdf or a word-document? The --signs in your :- are not minus signs - this is causing the error. Retype them to solve the issue and then you can analyze the predicates. How to know if chars looking the same are not the same? I would suggest using a diff tool (a program to compare files, as command line or with a gui (winmerge), even available online) or an ascii to hex converter like this.
Example queries which give you a hint what these predicates do:
?- predicate1([1,2,3],L).
?- append([1,2,3],[4,5],L).
?- predicate2wrapper([1,2,3],L).
?- predicate3([c,c],[a,a,b,b]).
?- predicate3([b,b],[a,a,b,b,c,c]).
?- predicate3([X,X],[a,a,c,b,b]).
?- predicate4([a,b],[a,c,b]).
?- predicate4([a,d],[a,c,b]).
?- member(a,[a,c,b]).
?- member(d,[a,c,b]).

`multifile` in combination with semweb `rdf_meta` for prefix processing in a predicate

SWI-prolog version: threaded, 64 bits, version 7.6.4
OS: Ubuntu bionic 18.04
Still working on learning prolog and ran into an interesting situation. I would like to use a predicate that is 'asserted' over multiple files (just makes the code look a little cleaner in organization), but that predicate also needs to be able to process rdf prefixes as part of the semweb package and it does not seem to work.
Here is a code block that might show the problem:
:- module(multifile1,
[
test/2
]
).
:- use_module(library(semweb/rdf_db)).
:- use_module(library(semweb/rdfs)).
:- multifile
multifile1:bar/1,
multifile1:foo/1.
:- rdf_meta
test(-, r),
foo(r).
test(bar, X) :-
bar(X).
test(foo, X) :-
foo(X).
multifile1:bar(abc) :-
format('bar: abc~n', []).
foo(rdf:about) :-
format('foo: rdf:about~n', []).
And asserting the same foo in another file:
:- module(multifile2,
[
]
).
:- use_module(library(semweb/rdf_db)).
:- use_module(library(semweb/rdfs)).
:- multifile
multifile1:foo/1.
:- rdf_meta
multifile1:foo(r).
multifile1:foo(rdf:type) :-
format('rdf:type~n', []).
In this form calling test(foo, rdf:about) works, but asserting test(foo, rdf:type) does not work. Is rdf_meta and multifile not supposed to work together or there is a bug in this code?
PS: I had added the multifile bar to make sure that works over multiple files.
I think I figured out. multifile and rdf_meta do work together. The bug in the code was related to the fact that I had defined foo in rdf_meta as foo(r). I think that expansion was causing confusion at compile time with regards to pattern match. Changing the definition to foo(-) fixed the problem. Hope this helps someone in the future.

How do you get only one output from a swi-prolog query?

How do I get only one output from a SWI-Prolog query? I have tried using cut (!) but it does not seem to work.
For example:
I already filled my knowledge base up with statements and I wanted to find any one name who is both female and is the mother of someone.
I have already tried:
mother(X,Y), female(X).
...but that gives me all of the X-__ and Y-__
I have also tried:
mother(X,Y), female(X), !.
... but that still gives me both the X-__ and Y__
I only want to find the X. Does anyone have any tips for me to somehow only get one?
?- setof(t, Y^ ( mother(X, Y), female(Y) ), _).
which will remove duplicates (redundant answers/solutions), too. Or using library(lambda):
?- X+\ ( mother(X, Y), female(Y) ).
which does not remove redundant answers.

Is There a Way to Consolidate Facts?

Is there a way to turn this:
genre(blues).
gere(hiphop).
genre(rock).
Into something like this:
genre(blues;hiphop;rock).
*I know this does not work, but does something similar to this exist.
You cannot consolidate facts, but you can turn them into a simple rule, like this:
genre(X) :- member(X, [blues, hiphop, rock]).
member/2 is a built-in list predicate in SWI to test list membership.
This lets you apply a predicate across all of the elements of a list, and will succeed only if all applications succeed.
test_list( _, [] ).
test_list( F, [H|T] ) :- P =.. [F,H], P, test_list( F, T ).
You could use this syntax
genre(X) :- X=blues ; X=hiphop ; X=rock.
but personally I advice the member/2 way...

Writing to file (Prolog)

I've been trying to loop through a list and writing it to a file, why is the following not working?
loop_through_list(List) :-
member(Element, List),
write(Element),
write(' '),
fail.
write_list_to_file(Filename,List) :-
tell(Filename), % open file to be written
loop_through_list(List),
told. % flush buffer
First, why it fails :
You use fail to provoke backtracking, which can be a good technique, but not there. Because it will make your predicate false in the end, when member has ran out of solutions. Then, once loop_through_list is false, told isn't reached and the writing isn't made properly (when I test it, the file is created but nothing is written).
If you use :
loop_through_list([]).
loop_through_list([Head|Tail]) :-
write(Head),
write(' '),
loop_through_list(Tail).
instead, it works.
But, even with this code working, you might want to use
open(Filename, write, Stream), write(Stream, Element) and close(Stream) instead of tell and told for the reasons explained in the link at the bottom of this answer.
For example :
loop_through_list(_File, []) :- !.
loop_through_list(File, [Head|Tail]) :-
write(File, Head),
write(File, ' '),
loop_through_list(File, Tail).
write_list_to_file(Filename,List) :-
open(Filename, write, File),
loop_through_list(File, List),
close(File).
or
loop_through_list(File, List) :-
member(Element, List),
write(File, Element),
write(File, ' '),
fail.
write_list_to_file(Filename,List) :-
open(Filename, write, File),
\+ loop_through_list(File, List),
close(File).
using your code and joel76 trick.
See Prolog how to save file in an existing file
It covers the same matter.
I fail to see the reason to do use this method to write a list to a file.
Programming in prolog should generally not involve loops;
besides, this is not a loop structure, it's more like a hack (or even abuse).
(and just like your case leads to unexpected bugs and problems)
Just use recursion and print the elements of the list:
write_list([]).
write_list([H|T]):-
write(H),
write(' '),
write_list(T).
more elegant and could be more efficient too.
other than that, using open/4 etc (ISO IO) instead of tell/1 etc (Edinburgh IO) is generally better; check false's post
predicate loop_through_list(List), always fails, so to succed you just have to write \+loop_through_list(List),

Resources