Creating a list from user input with swi-prolog - list

This is my first experience with Prolog. I am at the beginning stages of writing a program that will take input from the user (symptoms) and use that information to diagnose a disease. My initial thought was to create lists with the disease name at the head of the list and the symptoms in the tail. Then prompt the user for their symptoms and create a list with the user input. Then compare the list to see if the tails match. If the tails match then the head of the list I created would be the diagnosis. To start I scaled the program down to just three diseases which only have a few symptoms. Before I start comparing I need to build the tail of list with values read from the user but I can't seem to get the syntax correct.
This is what I have so far:
disease([flu,fever,chills,nausea]).
disease([cold,cough,runny-nose,sore-throat]).
disease([hungover,head-ache,nausea,fatigue]).
getSymptoms :-
write('enter symptoms'),nl,
read(Symptom),
New_Symptom = [Symptom],
append ([],[New_symptom],[[]|New_symptom]),
write('are their more symptoms? y or n '),
read('Answer'),
Answer =:= y
-> getSymptoms
; write([[]|New_symptom]).
The error occurs on the append line. Syntax Error: Operator Expected.
Any help with this error or the design of the program in general would be greatly appreciated.

This is one way to read a list of symptoms in:
getSymptoms([Symptom|List]):-
writeln('Enter Symptom:'),
read(Symptom),
dif(Symptom,stop),
getSymptoms(List).
getSymptoms([]).
You type stop. when you want to finish the list.
You would then need to decide what logic you want to match the way you have represented a disease.
A complete example:
:-dynamic symptom/1.
diagnose(Disease):-
retractall(symptom(_)),
getSymptoms(List),
forall(member(X,List),assertz(symptom(X))),
disease(Disease).
getSymptoms([Symptom|List]):-
writeln('Enter Symptom:'),
read(Symptom),
dif(Symptom,stop),
getSymptoms(List).
getSymptoms([]).
disease(flue):-
symptom(fever),
symptom(chills),
symptom(nausea).
disease(cold):-
symptom(cough),
symptom(runny_nose),
symptom(sore_throat).
disease(hungover):-
symptom(head_ache),
symptom(nausea),
symptom(fatigue).

create(L1):-read(Elem),create(Elem,L1).
create(-1,[]):-!.
create(Elem,[Elem|T]):-read(Nextel),create(Nextel,T).
go:- write('Creating a list'),nl,
write('Enter -1 to stop'),nl,
create(L),
write('List is:'),
write(L).

Related

Python 2.7: How to make a function print an undetermined amount of strings from a tuple

I'm making a text-based adventure game, and would like to have a universal 'look' function that uses an algorithm to tell the player how many and what objects are in a room instead of me having to write individual descriptions for each room. So it would work roughly like this:
lookround(things.bedroom)
You see:
a bed, which is the last on the right, across from Jacob's and to the left of Steve's,
and
a calendar, which is on a nail driven into the wall to the left of your bed
The objects are stored in the class 'things', which has a format that organises them with the object name first, and then the description of its location, then it repeats. That way, all the function has to do is print the first two tuples, then the next two, then the next two, and so on.
So, how would I get it to print out a number of tuples which have not been spoon fed to it?
Right now, I'm trying to use this:
def lookround(room):
print '''You see:'''
for len(room) % 2:
print ('{}, which is {},'.format(room))
The problems I'm having are that I'm getting a syntax error which points to the colon after len, and I'm not sure what I should put in .format() .
I've tried messing around with the syntax, but nothing's working.
class room(object):
things = ('a bed', 'to sleep in',
'a calendar', 'to look up the date',
'a clock', 'to wake up')
def lookround(room):
print '''You see:'''
for i in range(len(room.things)):
if not (i%2):
print ('{}, which is {},'.format(room.things[i], room.things[i+1]))
if i != len(room.things) - 2:
print 'and'
This should work with your current format. It might be a better idea to store things as a tuple of tuples, so you don't deal with the modulus business...

Checking the heads of lists of lists

I'm trying to write a function that filters on a list of lists however I can't manage to work out how. My first question of course is how to filter a list of lists
[[2,2,2],[1,2,3],[2,2,3]]
filter (==2)
The second thing I'm trying to work out is how to only filter the Head of each of the lists.
Eg for the above filter, I would expect an output of 2 from the first list, and 2 from the third list.
Any help would be much appreciated.
Cheers.
Maybe filter (==2) $ map (head) [[2,2,2],[1,2,3],[2,2,3]] ? But still the problem is very ambiguously stated.
Output:
[2,2]
EDIT:
As Thomas M. DuBuisson said head returns error when the list is empty according to its definition:
badHead :: a
badHead = errorEmptyList "head"
head [] = badHead
whereas take !_ [] = [].

Make list from list of lists with condition

I'm currently stucked with recursion over lists of lists.
The task is quite simple in any imperative language: iterate over every professor, iterate over professor's course list, and get every course that matches CourseNumber given as predicate argument to output var CourseList.
I have simple solution (other ones just fail with out of stack or returns empty list), but as you can see, it checks only if the head of the course's list matches cond.
get_teaching_courses(CourseNumber, CourseList) :-
findall(Course,
(
professor(_, [Course | _]),
member(CourseNumber, Course)
),
CourseList).
professor fact has next struct:
professor(Name, [ [CourseName , CourseNumber], .... ]).
I am thinking of making predicate over predicate, but I can't achieve it (something wrong with append I guess).
It's been like 2 days I've started learning prolog, and if you can give me any help, advice or link that can help me, I'd appreciate it.
example:
assertz(
professor(
'Bob',
[
['Math', 2],
['PE', 3]
]
)
).
Solution:
get_teaching_courses(CourseNumber, CourseList) :-
findall(CourseName,
(
professor(_, Course),
member([CourseName, CourseNumber], Course)
),
CourseList).
thanks to #CapelliC and his answer.
the problem is the incorrect pattern matching applied in member/2. Try
member([_,CourseNumber], Course)

Prolog - sending a list as a parameter to be displayed

I'm trying to write a program to find a route between towns, add the path to the list and then, ad the end display it.
I think adding to the list works, but I'm having the problem displaying the list, don't know how can I pass a list as a parameter to be used when it's done finding the path? Hope you guys can help. Here's the code:
connected(middlesbrough, stockton).
connected(middlesbrough, darlington).
connected(stockton, sunderland).
connected(darlington, thirsk).
connected(stockton, newcastle).
connected(newcastle, york).
connected(thirsk, york).
connected(york, leeds).
connected(leeds, huddersfield).
connected(leeds, dewsbury).
connected(huddersfield, manchester).
connected(dewsbury, manchester).
run(List):-
write('Enter Starting City :'),
read(Start),
write('Enter Finishing City :'),
read(End),
findroute(Start,End),
writeList([List]).
findroute(Start,End):-
connected(Start,End).
findroute(Start,End):-
add(Start, List, [Start | List]),
connected(Start,Link), findroute(Link,End).
add(A,B,[A|B]).
writeList([]).
writeList([Head | Tail]):-
write(Head),
nl,
writeList(Tail).
Your findroute/2 predicate does not return the list, so the output can't work.
The call should look something like this:findroute(Start,End,List)
Obviously, the findroute/2 predicate must be changed to findroute/3:
findroute(Start,End,[Start,End]):-
connected(Start,End).
findroute(Start,End,List):-
connected(Start,Link),
add(Start,Rest,List),
findroute(Link,End,Rest).
(hint: be sure you understand why the add/3 call works even though Rest is uninstantiated at that point. Otherwise your tutor won't believe that this code is your homework! ;-) )
You may want to add a cut at the end of the first clause if you only want to find the shortest route.
Finally, List is already a list, so don't put square brackets around it when calling writeList/1!

Prolog list adding

--the question has been edited--
Using this data, I need to create a list:
team(milan,1).
team(napoli,2).
team(lazio,3).
team(roma,4).
team(inter,4).
team(juventus,5).
So, given a query like:
check([milan,lazio,roma,inter]).
make a new list with their respective team number.
X=[1,3,4,4]
What I'm trying to do is creating a list, adding elements one at a time.
check([H|T]) :-
team(H,R),
append([R],_, X),
check(T).
Could someone help me complete this?
You need to find all the team numbers for which the name of the team is a member of the list of team names that you are interested in:
?- findall(Number, (
team(Name, Number),
member(Name, [milan, lazio, roma, inter])), Numbers).
Numbers = [1, 3, 4, 4].
To return the numbers in a given order, just apply member/2 before team/2, in this case member/2 generates names (in the given order), and team/2 maps them to numbers:
?- findall(Number, (
member(Name, [lazio, milan, inter]),
team(Name, Number)), Numbers).
Numbers = [3, 1, 4].
A lot of time since I used Prolog but an answer -more or less- would look like:
check([]) :- true.
check([X]) :- team(X,_).
check([X,Y]) :- team(X,N), team(Y,M), N < M.
check([X,Y|T]) :- check(X,Y), check([Y|T]).
See this question for a very similar problem.
From what you say you might be better off making a list and then sorting it. That way you'd know the list is in order. Of course it's tricky in that you are sorting on the team ranks, not the alphabetic order of their names.
But the question you asked is how to check the list is in sorted order, so let's do it.
check([ ]). % just in case an empty list is supplied
check([_]). % singleton lists are also in sort order
check([H1,H2|T]) :-
team(H1,R1),
team(H2,R2),
R1 <= R2,
check([H2|T]).
Note that the recursion reduces lists with at least two items by one, so the usual termination case will be getting down to a list of length one. That's the only tricky part of this check.
Added in response to comment/question edit:
Sure, it's good to learn a variety of simple "design patterns" when you are getting going with Prolog. In this case we want to "apply" a function to each item of a list and build a new list that contains the images.
mapTeamRank([ ],[ ]). % image of empty list is empty
mapTeamRank([H|T],[R|S]) :-
team(H,R),
mapTeamRank(T,S).
So now you have a predicate that will turn a list of teams LT into the corresponding list of ranks LR, and you can "check" this for sorted order by calling msort(LR,LR):
check(LT) :-
mapTeamRank(LT,LR),
msort(LR,LR).