Prolog: Downcase all atoms in a list - list

I'm trying to write a Prolog program that needs to take a user's natural language input and match it against a set of atoms. I'm using SWI Prolog's readln/1 to get input and put it in a list of atoms, but I don't have any guarantee of the case of the user input, so I want to just downcase all of the input I get before I try matching. What I have right now is:
downcase_list(AnyCase, LowerCase) :- dcl(AnyCase, X), flatten(X,LowerCase).
dcl([], List) :- List.
dcl([Head|Rest], []) :- downcase_atom(Head,X), dcl(Rest,X).
dcl([Head|Rest], List) :- downcase_atom(Head,X), dcl(Rest, [List|X]).
Appending using [List|X] seems to be my problem, but I don't know how to fix it, since I've already tried using append/3 and just got an infinite loop:
downcase_list([], List) :- List.
downcase_list([Head|Rest], []) :- downcase_atom(Head,X), downcase_list(Rest, X).
downcase_list([Head|Rest], NewList) :- downcase_atom(Head,X), append(NewList,X,Z), writeln(Z), downcase_list(Rest,Z).
I am very new to Prolog (I would classify myself as a Lisp programmer at this point), so it's very possible I'm missing something elementary. Help?

If you already have a list of atoms, to downcase them you have to apply a mapping with maplist/3 and downcase_atom/2:
downcase_list(AnyCaseList, DownCaseList):-
maplist(downcase_atom, AnyCaseList, DownCaseList).

Related

Best way to remove the first elements from each list in a list of lists in Prolog?

I am trying to remove the first element of every list in a list of lists.
For example, to list [[1,2],[3,4]], I should return [[2],[4]].
In most situations, this code below will work fine:
remove_firstElem([],[]).
remove_firstElem([[_H|T]|Ls],[T|L]) :-
remove_firstElem(Ls,L).
But for lists like [[1],[2]], I would like it to return [] rather than [[],[]].
What I tried so far looks like:
remove_firstElem([_H|Ls],L) :-
length(_H,1),
remove_firstElem(Ls,L).
But it returns [ ],[[ ]],[[ ]],[[ ],[ ]] and I really don't know what's wrong with it.
Can anyone help me to fix it? Thanks for any help!
If I understand it correctly, you want to pop the head of the list, but in case the list contains only one element (or none at all), that list should be removed.
We can check if the sublist contains at least two elements with the pattern:
pop_lists([[_,H2|T]|TA],[[H2|T]|TB]) :-
pop_lists(TA,TB).
so here we have a pattern [_,H2|T] for the first list. The _ binds with the first element, H2 with the second element, and the remaining elements with the tail.
Lists that can not unify with that pattern are the empty list, or a list with one element. So in that case we simply ignore them:
pop_lists([[]|TA],TB) :-
pop_lists(TA,TB).
pop_lists([[_]|TA],TB) :-
pop_lists(TA,TB).
In case we reach the end of the list, of course we unify the filter with the empty list as well:
pop_list([],[]).
we better put this clause on the first line to make our predicate more multidirectional. So in full, we have the following solution:
pop_list([],[]).
pop_list([[_,H2|T]|TA],[[H2|T]|TB]) :-
pop_list(TA,TB).
pop_list([[]|TA],TB) :-
pop_list(TA,TB).
pop_list([[_]|TA],TB) :-
pop_list(TA,TB).
We can further reorder the statements, such that the amount of backtracking is less:
pop_list([],[]).
pop_list([[]|TA],TB) :-
pop_list(TA,TB).
pop_list([[_]|TA],TB) :-
pop_list(TA,TB).
pop_list([[_,H2|T]|TA],[[H2|T]|TB]) :-
pop_list(TA,TB).
Easier way:
list_tail([_|Es], Es).
maplist(list_tail, Input, Output).

Inserting value into the begining of each sublist

I'm currently writing a predicate that will run through a list of lists and insert a value I have calculated onto the beginning of the list
Step one is easy, just perform the calculation for each list and unify variable N with it.
checkthrough([]).
checkthrough([H|T]):-
count_validentries(H,N),
checkthrough(T).
What I'm trying to achieve now is to put that variable N onto the beginning of each of my sublists, so each list begins with the count of valid entries.
I have attempted to do this using an accumulator. Attempting to start with an empty list, and to every time add the new value N and the head of the list to it:
checkthrough([],Sofar,Lastone).
checkthrough([H|T],Sofar,Lastone):-
count_validentries(H,N),
Newsofar is [N,H|Sofar],
checkthrough(T,Newsofar,Lastone).
I'm quite sure I'm making a really stupid mistake somewhere along the lines. This is not valid Prolog syntax, failing with Arithmetic:' [2 internal variables]' is not a function.
Does anyone have any tips please?
Using meta-predicate maplist/3 and Prolog lambda simply write:
?- use_module(library(lambda)).
?- maplist(\Es^[N|Es]^count_validentries(Es,N), Ess, Xss).
Also, I'd guess that you're really looking for (-)/2 pairs which is how key-value pairs are commonly represented—by library predicates and the built-in predicate keysort/2. Consider:
?- Ess = [[a,b,c],[d,e],[],[f]],
maplist(\Es^(N-Es)^length(Es,N), Ess, Xss),
keysort(Xss, Yss).
Ess = [ [a,b,c], [d,e], [], [f]],
Xss = [3-[a,b,c], 2-[d,e], 0-[], 1-[f]],
Yss = [0-[], 1-[f], 2-[d,e], 3-[a,b,c]].
Maybe
checkthrough([],Sofar,Sofar).
checkthrough([H|T],Sofar,Lastone):-
count_validentries(H,N),
checkthrough(T,[[N|H]|Sofar],Lastone).
but you'll end up with the list reversed. Keeping it simpler will help
checkthrough([],[]).
checkthrough([H|T],[[N|H]|Rest]):-
count_validentries(H,N),
checkthrough(T,Rest).
or better, if you're running a recent version of SWI-Prolog:
checkthrough(L,L1) :-
maplist([E,E1]>>(count_validentries(E,N),E1=[N|E]), L,L1).

Removing heads from lists in Prolog

I'm trying to write a predicate to remove the head from every list in list of lists and add the tails to a new list. The resulting list should be returned as the second parameter.
Here's the attempt:
construct_new(S,New) :-
New = [],
new_situation(S,New).
new_situation([],_).
new_situation([H|T], New) :-
chop(H, H1),
new_situation(T, [H1|New]).
chop([_|T], T).
You would call it like this:
construct_new([[x,x],[b,c],[d,e,f]],S).
This, however, only produces output true..
Step-by-step execution
Your query is construct_new(Input,Output), for some instanciated Input list.
The first statement in construct_new/2 unifies Output (a.k.a. New) with the empty list. Where is the returned list supposed to be available for the caller? Both arguments are now unified.
You call new_situation(Input,[])
You match the second clause new_situation([H|T],[]), which performs its task recursively (step 4, ...), until ...
You reach new_situation([],_), which successfully discards the intermediate list you built.
Solutions
Write a simple recursive predicate:
new_situation([],[]).
new_situation([[_|L]|T],[L|R]) :-
new_situation(T,R).
Use maplist:
construct_new(S,R) :-
maplist(chop,S,R).
Remark
As pointed out by other answers and comments, your predicates are badly named. construct_new is not a relation, but an action, and could be used to represent almost anything. I tend to like chop because it clearly conveys the act of beheading, but this is not an appropriate name for a relation. repeat's list_head_tail(L,H,T) is declarative and associates variables to their roles. When using maplist, the other predicate (new_situation) doesn't even need to exist...
...even though guillotine/3 is tempting.
This could be done with a DCG:
owth(Lists, Tails) :-
phrase(tails(Tails), Lists).
tails([]) --> [].
tails([T|Tails]) --> [[_|T]], tails(Tails).
Yielding these queries:
| ?- owth([[x,x],[b,c],[d,e,f]], T).
T = [[x],[c],[e,f]] ? ;
no
| ?- owth(L, [[x],[c],[e,f]]).
L = [[_,x],[_,c],[_,e,f]]
yes
(owth = Off with their heads! or, if used the other direction, On with their heads!)
If you also want to capture the heads, you can enhance it as follows:
owth(Lists, Heads, Tails) :-
phrase(tails(Heads, Tails), Lists).
tails([], []) --> [].
tails([H|Hs], [T|Tails]) --> [[H|T]], tails(Hs, Tails).
We use meta-predicate maplist/[3-4] with one of these following auxiliary predicates:
list_tail([_|Xs],Xs).
list_head_tail([X|Xs],X,Xs).
Let's run some queries!
?- maplist(list_head_tail,[[x,x],[b,c],[d,e,f]],Heads,Tails).
Heads = [x,b,d],
Tails = [[x],[c],[e,f]].
If you are only interested in the tails, use maplist/4 together with list_head_tail/3 ...
?- maplist(list_head_tail,[[x,x],[b,c],[d,e,f]],_,Tails).
Tails = [[x],[c],[e,f]].
... or, even simpler, maplist/3 in tandem with list_tail/2:
?- maplist(list_tail,[[x,x],[b,c],[d,e,f]],Tails).
Tails = [[x],[c],[e,f]].
You can also use the somewhat ugly one-liner with findall/3:
?- L = [[x,x],[b,c],[d,e,f]],
findall(T, ( member(M, L), append([_], T, M) ), R).
R = [[x], [c], [e, f]].
(OK, technically a two-liner. Either way, you don't even need to define a helper predicate.)
But definitely prefer the maplist solution that uses chop as shown above.
If you do the maplist expansion by hand, and name your chop/2 a bit better, you would get:
lists_tails([], []).
lists_tails([X|Xs], [T|Ts]) :-
list_tail(X, T),
lists_tails(Xs, Ts).
And since you can do unification in the head of the predicate, you can transform this to:
lists_tails([], []).
lists_tails([[_|T]|Xs], [T|Ts]) :-
lists_tails(Xs, Ts).
But this is identical to what you have in the other answer.
Exercise: why can't we say:
?- maplist(append([_]), R, [[x,x],[b,c],[d,e,f]]).

Reading list from a file

I don't have much experience in Prolog.
add(first, second) :-
see('telefon_375319.txt'),
read(L),
seen,
M = [[first, second] | L],
tell('telefon_375319.txt'),
write(M),
nl,
told.
The purpose of the above code is to:
Read the list (which is a list of list) from a file (into L).
Add the list [first, second] at the beginning of the list (it might be at the end or even in the middle).
Save it to a file.
The result I get in the file is following:
[[x, y], end_of_file].
The result should be:
[[x, y], and here should be the rest of the list].
I don't know why ,but Prolog read a text end_of_file into L instead of the list which is stored in the file.
What's wrong?
end_of_file is not text. It’s atom and it’s read when the file ends. But in my SWI Prolog I see that an empty line must me placed at the end of the file in order to read it correctly. Searching for relevant info on that.
I modified the original slightly to use variables, not atoms. I also added writing a period (.) after the list that's written since read expects to see it:
add(First, Second) :-
see('telefon_375319.txt'),
read(L),
seen,
M = [[First, Second] | L],
tell('telefon_375319.txt'),
write(M), write('.'),
nl,
told.
Contents of telefon_375319.txt:
[[a,b],[c,d]].
Then run:
| ?- add(x, y).
yes
New contents of telefon_375319.txt:
[[x,y],[a,b],[c,d]].
Run:
| ?- add(z, w).
New contents of telefon_375319.txt:
[[z,w],[x,y],[a,b],[c,d]].
Other than the two changes that I made which I mentioned above, I don't see anything wrong with the predicate based upon the described desired behavior. I ran this on GNU Prolog and SWI Prolog on Linux, and SWI Prolog on Windows 7 and it worked as expected in all cases. The text file ends in a single \n in the case of Linux, and \r\n in the case of Windows.

How can I check if an element in the list is an empty list: []?

How can I check if an element in the list is an empty list: [] ?
I've got the following:
display_degrees([A,B,C,D]):- write(B).
display_degrees([A,B,C,D]):- B==[], nl,write('has no degree'), nl, !.
When I enter in something like:
display_degrees([1,[],3,4]).
I just get: [] instead of 'has no degree'. Is my syntax wrong? Can I not add a clause to this predicate like this?
You're getting this behavior because proof search stops when a goal has succeeded. When you type
display_degrees([1,[],3,4]).
the first rule unifies, and it writes B. Since it was a success, it stops. You can ask Prolog to keep searching, and then it will find the second clause. In swipl, I get
?- [foo].
?- display_degrees([1,[],3,4]).
[]
true r % I type 'r' there
has no degree
true.
If you're just learning Prolog, I suggest you avoid the cut operator ! for some time. Also, doing IO is not the most intuitive thing. I would try some exercises with defining things like natural numbers and recursive functions. E.g., plus:
plus(z, X, X).
plus(s(X), Y, s(Z)) :- plus(X, Y, Z).
The problem with what you have is that the more general rule will fire first. You could switch the order:
display_degrees([A,[],C,D]) :- nl, write('has no degree'), nl, !.
display_degrees([A,B,C,D]) :- write(B).
I could just as well have written for the first predicate:
display_degrees([A,B,C,D]) :- B == [], nl, write('has no degree'), nl, !.
But the "shortcut" I show initially is more idiomatic for a Prolog predicate like this.
I kept the cut since you know you deterministically want one choice. The first rule will match if and only if the second list element is [].
| ?- display_degrees([1,[],3,4]).
has no degree
yes
| ?- display_degrees([1,2,3,4]).
2
yes
| ?-