input and output chapter 6. warning n there is absolutely no need to do i/o for assignment #2 –all...
TRANSCRIPT
Input and OutputInput and Output
Chapter 6Chapter 6
WarningWarning
There is absolutely no need to do I/O for There is absolutely no need to do I/O for assignment #2assignment #2– all the I/O that needs to be done will be done all the I/O that needs to be done will be done
automatically by Prologautomatically by Prolog
Still, we sometimes want a program to Still, we sometimes want a program to interact with a user in a more natural wayinteract with a user in a more natural way
Simple OutputSimple Output
write/1 writes its argument into the consolewrite/1 writes its argument into the console nl/0 writes a new-line characternl/0 writes a new-line character
– ends the current lineends the current line write_ln/1 = (write/1, nl)write_ln/1 = (write/1, nl)hello_world :-hello_world :-
write_ln(‘Hello, World!’).write_ln(‘Hello, World!’).
Simple InputSimple Input
read/1 reads a term from the consoleread/1 reads a term from the console– term can be number/atom/list/…term can be number/atom/list/…– end with a periodend with a period– everything written just like in Prologeverything written just like in Prolog
read_int(N) :-read_int(N) :- read(N),read(N), integer(N).integer(N).
Read and WriteRead and Write
Read a name for a studentRead a name for a student?- ?- read_name(100176, Student).read_name(100176, Student).What is the name for student #100176? What is the name for student #100176? mark.mark.Student = student(100176, mark)Student = student(100176, mark)YesYes
Read and WriteRead and Write
Read a name for a studentRead a name for a studentread_name(ID, student(ID, Name)) :-read_name(ID, student(ID, Name)) :-
write(‘What is the name for student #’),write(‘What is the name for student #’),write(ID),write(ID),write(‘? ’),write(‘? ’),read(Name).read(Name).
Note: SWI Prolog won’t print |: prompt if there’s already output on the line
Yes Or No?Yes Or No?
Utility predicateUtility predicate Succeeds if user enters yesSucceeds if user enters yes Fails if user enters anything elseFails if user enters anything else
user_says_yes :-user_says_yes :-
write(‘Enter yes or no: ’),write(‘Enter yes or no: ’),
read(yes).read(yes).Reads a term & tries to unify it with yes.Fails if user enters anything other than yes.
ExerciseExercise
Write read_names/2Write read_names/2– takes a list of student IDs and reads a name for takes a list of student IDs and reads a name for
each student IDeach student ID– use read_name/2 as defined aboveuse read_name/2 as defined above?- ?- read_names([10076, 20012], L).read_names([10076, 20012], L).What is the name for student #10076? What is the name for student #10076? mark.mark.What is the name for student #20012? What is the name for student #20012? cathy.cathy.L = [student(10076,mark), student(20012,cathy)]L = [student(10076,mark), student(20012,cathy)]YesYes
SolutionSolution
% base case – no IDs% base case – no IDsread_names([], []).read_names([], []).
% recursive case: read name for first ID & recur% recursive case: read name for first ID & recurread_names([ID|IDs], [N|Ns]) :-read_names([ID|IDs], [N|Ns]) :-
read_name(ID, N),read_name(ID, N),read_names(IDs, Ns).read_names(IDs, Ns).
Reading in a LoopReading in a Loop
““Loop” above is controlled by a listLoop” above is controlled by a list– not not reallyreally a loop, but that’s how it acts a loop, but that’s how it acts
Reading a value for each element of the listReading a value for each element of the list There are other common “loop” strategiesThere are other common “loop” strategies
Sentinel Controlled LoopsSentinel Controlled Loops
Keep reading until some special valueKeep reading until some special value– similar controls used in imperative languagessimilar controls used in imperative languages
PromptAndRead(N);PromptAndRead(N);while (N while (N SENTINEL) SENTINEL)
Process(N);Process(N);PromptAndRead(N);PromptAndRead(N);
Note structure:Note structure:– read, loop(test, process, read)read, loop(test, process, read)
If reading positive numbers,SENTINEL may be 0 or –1
Sentinels in PrologSentinels in Prolog
Similar structureSimilar structure– read, recur(test, process, read)read, recur(test, process, read)– need a predicate for the recursionneed a predicate for the recursion– need a new variable for next valueneed a new variable for next value– separate predicate may be used to start offseparate predicate may be used to start off
Sentinel can be anythingSentinel can be anything– can be a different can be a different typetype than other objects read than other objects read– often use atom often use atom stopstop as a sentinel as a sentinel
Generic Sentinel CodeGeneric Sentinel Code
read_main :-read_main :-read(N),read(N),read_loop(N, …).read_loop(N, …).
read_loop(stop, …) :-read_loop(stop, …) :-
!.!.read_loop(N, …) :-read_loop(N, …) :-
process(N, …),process(N, …),read(Next),read(Next),read_loop(Next, …).read_loop(Next, …).
Main predicatereads first itemstarts “loop” running
Base case – got the sentinelcommit so don’t process sentinel
Recursive caseprocess the value readread the next valuerecur
Sentinel CodeSentinel Code
cuber :-cuber :-read_number(N),read_number(N),cuber_loop(N).cuber_loop(N).
cuber_loop(stop) :-cuber_loop(stop) :-
!.!.cuber_loop(N) :-cuber_loop(N) :-
print_cube(N),print_cube(N),read_number(Next),read_number(Next),cuber_loop(Next).cuber_loop(Next).
read_number(N) :-read_number(N) :-write_ln(‘Enter …’),write_ln(‘Enter …’),read(N).read(N).
print_cube(N) :-print_cube(N) :-write(‘The cube of ’),write(‘The cube of ’),write(N),write(N),write(‘ is ’),write(‘ is ’),N3 is N^3,N3 is N^3,write_ln(N3).write_ln(N3).
Sentinel Control ExerciseSentinel Control Exercise
Write a sentinel controlled “loop” to read in Write a sentinel controlled “loop” to read in a person’s name and print out their parent’s a person’s name and print out their parent’s names (family_1.PL already loaded)names (family_1.PL already loaded)
?- ?- parentage.parentage.Enter the person’s name or quit: Enter the person’s name or quit: bob.bob.bob’s parent is pam.bob’s parent is pam.
Enter the person’s name or quit: Enter the person’s name or quit: quit.quit.Yes Yes
SolutionSolution
parentage :-parentage :-read_name(N),read_name(N),parentage_loop(N).parentage_loop(N).
parentage_loop(quit) :-parentage_loop(quit) :-!.!.
parentage_loop(N) :-parentage_loop(N) :-print_parent(N),print_parent(N),read_name(Next),read_name(Next),parentage_loop(Next).parentage_loop(Next).
read_name(N) :-read_name(N) :-write(‘Enter …’),write(‘Enter …’),read(N).read(N).
print_parent(N) :-print_parent(N) :-parent(P, N),parent(P, N),write(N),write(N),write(‘\’s parent is ’),write(‘\’s parent is ’),write(P),write(P),write(‘.\n\n’).write(‘.\n\n’).
Special CharactersSpecial Characters
Note how to print a single quote:Note how to print a single quote:– \’ inside the single quotes\’ inside the single quotes– ““escape sequence”escape sequence”
Can also print end-of-line character (\n)Can also print end-of-line character (\n)– don’t need write_ln – just for conveniencedon’t need write_ln – just for convenience
Others as in c and JavaOthers as in c and Java
Checking InputChecking Input
May want to check input to see if it’s validMay want to check input to see if it’s valid– number or stop for cubernumber or stop for cuber– atom for parentageatom for parentage
This also a loopThis also a loop– read, loop(test, warn, read)read, loop(test, warn, read)
Can do this with a modified sentinelCan do this with a modified sentinel– stop when you get valid inputstop when you get valid input
Type TestingType Testing
Can check what Can check what kindkind of value a variable has of value a variable has– atom(X) – X’s value is an atom (not a number)atom(X) – X’s value is an atom (not a number)– number(X), integer(X), float(X)number(X), integer(X), float(X)– compound(X) – X’s value is a termcompound(X) – X’s value is a term
Can check Can check whetherwhether X has a value X has a value– var(X) – X is unboundvar(X) – X is unbound– nonvar(X) – X is boundnonvar(X) – X is bound– ground(X) – X has no variables left in it at allground(X) – X has no variables left in it at all
Checking for Valid InputChecking for Valid Input
read_number_or_stop(N) :-read_number_or_stop(N) :-write(‘Enter a number or the word stop: ’),write(‘Enter a number or the word stop: ’),read(Try),read(Try),read_number_test(Try, N).read_number_test(Try, N).
read_number_test(N, N) :-read_number_test(N, N) :-(integer(N) ; N = stop), !.(integer(N) ; N = stop), !.
read_number_test(Try, N) :-read_number_test(Try, N) :-write(‘That is invalid input. Please try again: ’),write(‘That is invalid input. Please try again: ’),read(Next),read(Next),read_number_test(Next, N).read_number_test(Next, N).
About the SolutionAbout the Solution
Uses an extra predicateUses an extra predicate Can avoid thatCan avoid that
– put test in read_number itselfput test in read_number itself– recur on read_numberrecur on read_number
Necessary changeNecessary change– first read into a new variablefirst read into a new variable– gets bound with N only if it’s OKgets bound with N only if it’s OK
Modified SolutionModified Solution
read_number_or_stop(N) :-read_number_or_stop(N) :-write(‘Enter a number or the word stop: ’),write(‘Enter a number or the word stop: ’),read(Input),read(Input),((
(integer(Input) ; Input = stop), !, N = Input(integer(Input) ; Input = stop), !, N = Input;;
write_ln(‘Invalid input. Please try again.’),write_ln(‘Invalid input. Please try again.’),read_number_or_stop(N)read_number_or_stop(N)
).).
ExerciseExercise
Do the same for the read_name loopDo the same for the read_name loop– should read an atomshould read an atom– do do notnot use a helper predicate use a helper predicate
read_name(N) :-read_name(N) :-write(‘Enter a name or quit: ’),write(‘Enter a name or quit: ’),read(N).read(N).
?- ?- read_name(N).read_name(N).Enter a name or quit: Enter a name or quit: student(10076, mark).student(10076, mark).That is not a valid name. Please try again.That is not a valid name. Please try again.
SolutionSolution
read_name(N) :-read_name(N) :-write(‘Enter a name or quit: ’),write(‘Enter a name or quit: ’),read(Input),read(Input),((
atom(Input), !, N = Inputatom(Input), !, N = Input;;
write_ln(‘Invalid input. Please try again.’),write_ln(‘Invalid input. Please try again.’),read_name(N)read_name(N)
).).
File Input/OutputFile Input/Output
Above does input/output at consoleAbove does input/output at console Can also read from/write to filesCan also read from/write to files Use the Use the samesame predicates predicates
– read/1, write/1read/1, write/1 Just need to indicate that I/O should be Just need to indicate that I/O should be
from/to a given filefrom/to a given file
File InputFile Input
Tell Prolog to look in a given fileTell Prolog to look in a given file Predicate is called “see”Predicate is called “see”
– not “look” or “look_at”not “look” or “look_at”
?- ?- see(‘data.txt’), read(FileItem).see(‘data.txt’), read(FileItem).FileItem = data_item(1)FileItem = data_item(1)YesYes
% data.txt% (read skips comments)data_item(1).data_item(2).another_item.and_another.and_another.30.
See PersistsSee Persists
Prolog will continue to “see” the file until Prolog will continue to “see” the file until you say otherwiseyou say otherwise
Say otherwise by using seen/0Say otherwise by using seen/0?- ?- read(FI2), seen, read(N).read(FI2), seen, read(N).|: |: from_console.from_console.FI2 = data_item(2)FI2 = data_item(2)N = from_consoleN = from_consoleYesYes
Prolog returns to where it was reading from before
here the consolebut could be another file
File OutputFile Output
Use tell/1 and told/0Use tell/1 and told/0– just like see/1 and seen/0just like see/1 and seen/0
?- ?- tell(‘outfile.txt’), write(fred), told.tell(‘outfile.txt’), write(fred), told.
YesYes Note: does not automatically add periodsNote: does not automatically add periods
– if you want to make a Prolog readable file, you if you want to make a Prolog readable file, you must add the periods yourselfmust add the periods yourself
– ……, write(fred), write_ln(‘.’), …, write(fred), write_ln(‘.’), …
End of FileEnd of File
What if there’s no file there to read?What if there’s no file there to read?– File doesn’t exist ERRORFile doesn’t exist ERROR
What if it’s empty or you’ve read it all?What if it’s empty or you’ve read it all?– read succeeds(!)read succeeds(!)– binds argument to atom end_of_filebinds argument to atom end_of_file– use sentinel controlled loopuse sentinel controlled loop
ExerciseExercise
Write a loop to read and print every term Write a loop to read and print every term from a given filefrom a given file– one term per lineone term per line– switch back to regular input when doneswitch back to regular input when done
?- ?- show_terms(‘data.txt’).show_terms(‘data.txt’).data_item(1)data_item(1)data_item(2)data_item(2)……
SolutionSolution
show_terms(File) :-show_terms(File) :-see(File),see(File),read(N),read(N),show_term_loop(N),show_term_loop(N),seen.seen.
show_term_loop(end_of_file) :- !.show_term_loop(end_of_file) :- !.show_term_loop(N) :-show_term_loop(N) :-
write_ln(N),write_ln(N),read(Next),read(Next),show_term_loop(Next).show_term_loop(Next).
No need to prompt for inputit’s a file
Going Back to the ConsoleGoing Back to the Console
seen & told will return to seen & told will return to previousprevious file file– to console if there was no previous fileto console if there was no previous file
What if want to switch temporarily to What if want to switch temporarily to console & then resume the file?console & then resume the file?– special argument: the atom userspecial argument: the atom user– see(user), tell(user), …, seen, told.see(user), tell(user), …, seen, told.
ExerciseExercise
Modify show_term_loop/1 to pause if it Modify show_term_loop/1 to pause if it reads the atom stopreads the atom stop– it should ask the user whether it should it should ask the user whether it should
continuecontinue– continues only if user answers yescontinues only if user answers yes– bonus – make sure file gets closed even if the bonus – make sure file gets closed even if the
user says not to continue (user says not to continue (i.e.i.e. succeed even if succeed even if user says not to continue reading)user says not to continue reading)
New Rule (2New Rule (2ndnd Position) Position)
show_term_loop(stop) :-show_term_loop(stop) :-write_ln(‘Stop encountered!’),write_ln(‘Stop encountered!’),write(‘Continue (yes or no)? ’),write(‘Continue (yes or no)? ’),see(user), read(Response), seen,see(user), read(Response), seen,((
Response=yes, !, read(N), Response=yes, !, read(N), show_term_loop(N)show_term_loop(N);;
truetrue).).
May also want to tell(user), …, toldJust in case user has directed output to a file
Character I/O and StringsCharacter I/O and Strings
Chapter 6Chapter 6
Character Input/OutputCharacter Input/Output
Above requires files to have terms in themAbove requires files to have terms in them– that’s not always the casethat’s not always the case
Can also do input/output at character levelCan also do input/output at character level Use get0/1 and get/1 to read a characterUse get0/1 and get/1 to read a character
– get0/1 gets get0/1 gets very nextvery next character character– get/1 skips white-space (gets next get/1 skips white-space (gets next non-blanknon-blank))
Use put/1 to write a characterUse put/1 to write a character
Reading a CharacterReading a Character
?- ?- get(C).get(C).|: |: aaC = 97C = 97YesYes Prolog uses ASCII for charactersProlog uses ASCII for characters
– 97 is the ASCII code of the lowercase A97 is the ASCII code of the lowercase A It’ll print an a if you It’ll print an a if you put(97).put(97).
Getting a SpaceGetting a Space
?- get0(C).?- get0(C).|: |: C = 32C = 32YesYes?- get0(C).?- get0(C).|: |: C = 10C = 10YesYes get0/1 can also get regular charactersget0/1 can also get regular characters
Type space followed by return/enter
Type just return/enter
End of FileEnd of File
Try to get/1 or get0/1 past end of fileTry to get/1 or get0/1 past end of file– returns –1returns –1
?- ?- get0(C).get0(C).|: |: C = –1C = –1YesYes
Type ^D (control-D) or ^Z
Converting To/From ASCIIConverting To/From ASCII
Can use 0’a to generate ASCII for aCan use 0’a to generate ASCII for a– zero, single quote, single printable characterzero, single quote, single printable character
?- ?- X = 0’a.X = 0’a.X = 97X = 97 Works for other characters, tooWorks for other characters, too
– slight problems with command line entryslight problems with command line entry?- ?- X = (0’ ).X = (0’ ).X = 32X = 32
Squeezer ProgramSqueezer Program
Read a line of charactersRead a line of characters– compress multiple spaces into just onecompress multiple spaces into just one– stop when read a periodstop when read a period
squeeze_loop(0'.) :-squeeze_loop(0'.) :- % period% period !,!, % commit% commit put(0'.).put(0'.). % print it% print itsqueeze_loop(0' ) :-squeeze_loop(0' ) :- % space% space
……
0’. = 46but who cares?
0’ = 32
More SqueezerMore Squeezer
squeeze_loop(0' ) :-squeeze_loop(0' ) :- % space% space !, !, % commit% commit put(0’ ),put(0’ ), % print it% print it get(C),get(C), % read next non-space% read next non-space squeeze_loop(C).squeeze_loop(C). % continue% continuesqueeze_loop(A) :-squeeze_loop(A) :- % other% other put(A),put(A), % print it% print it get0(C),get0(C), % read next char (maybe blank)% read next char (maybe blank) squeeze_loop(C).squeeze_loop(C). % continue% continue
ExerciseExercise
Write a predicate read_sentence/1 that reads Write a predicate read_sentence/1 that reads characters up to the next periodcharacters up to the next period– stores list of characters read in its argumentstores list of characters read in its argument
?- ?- read_sentence(L).read_sentence(L).|: OK.|: OK.L = [79, 75]L = [79, 75]
ASCII codes:Capital 0 is 79Capital K is 75
Period (46) not kept
SolutionSolution
read_sentence(L) :-read_sentence(L) :-get(C),get(C),sentence_loop(C, L).sentence_loop(C, L).
sentence_loop(0’., []) :-sentence_loop(0’., []) :-!.!.
sentence_loop(A, [A|T]) :-sentence_loop(A, [A|T]) :-get0(C),get0(C),sentence_loop(C, T).sentence_loop(C, T).
Get first characterand start loop
Sentinel period dropped
Keep other lettersand continue
Converting To/From ASCIIConverting To/From ASCII
char_code/2 does conversionchar_code/2 does conversion?- ?- char_code(a, ASCII).char_code(a, ASCII).ASCII = 97ASCII = 97?- ?- char_code(L, 32).char_code(L, 32).L = ‘ ’L = ‘ ’?- ?- char_code(L, 10).char_code(L, 10).L = ‘\n’L = ‘\n’
Atoms & ASCII ConversionAtoms & ASCII Conversion
name/2 converts atoms to their ASCII codesname/2 converts atoms to their ASCII codes– and and vice versavice versa
Read a sentence and convert it to an atomRead a sentence and convert it to an atom?- ?- read_sentence(L), name(A, L).read_sentence(L), name(A, L).|: |: This is a sentence – soon an atom.This is a sentence – soon an atom.L = [84, 104, 105, 115, 32, 105, 115, 32, 97|...]L = [84, 104, 105, 115, 32, 105, 115, 32, 97|...]A = ‘This is a sentence – soon an atom’A = ‘This is a sentence – soon an atom’
ExerciseExercise
Write a predicate read_word/1 that reads a Write a predicate read_word/1 that reads a single wordsingle word– a word is any sequence of a word is any sequence of lettersletters terminated by terminated by
anything other than a letteranything other than a letter You will need a predicate is_letter/1 that You will need a predicate is_letter/1 that
succeeds if its argument is a(n ASCII) lettersucceeds if its argument is a(n ASCII) letter– letters are letters are betweenbetween 0’a and 0’z or 0’A and 0’Z 0’a and 0’z or 0’A and 0’Z– write this predicate, toowrite this predicate, too
SolutionSolution
read_word(W) :-read_word(W) :- get(C),get(C), read_word_loop(C, L),read_word_loop(C, L), name(W, L).name(W, L).read_word_loop(C, [C|L]) :-read_word_loop(C, [C|L]) :-
is_letter(C), !,is_letter(C), !, get0(Next),get0(Next), read_word_loop(Next, L).read_word_loop(Next, L).read_word_loop(C, []).read_word_loop(C, []).
is_letter(C) :- is_letter(C) :- between(0'A, 0'Z, C).between(0'A, 0'Z, C).
is_letter(C) :- is_letter(C) :- between(0'a, 0'z, C).between(0'a, 0'z, C).
Base at endC is knownno chance infinite rec.
Use get0 instead of getdon’t skip spaces
String ManipulationString Manipulation
““Prolog” = [80, 114, 111, 108, 111, 103]Prolog” = [80, 114, 111, 108, 111, 103]
StringsStrings
Double-quoted strings are lists of charactersDouble-quoted strings are lists of characters– each character an ASCII codeeach character an ASCII code
?- ?- X = “String”.X = “String”.
X = [83, 116, 114, 105, 110, 103]X = [83, 116, 114, 105, 110, 103] Can get strings to print as stringsCan get strings to print as strings?- ?- _X = “String”, string_to_list(S, _X)._X = “String”, string_to_list(S, _X).
S = “String”S = “String”
Strings in double-quotes
String ManipulationString Manipulation
Treat strings as listsTreat strings as lists Append a useful predicateAppend a useful predicate
– append one string/list to anotherappend one string/list to another– take strings aparttake strings apart
simple_plural(String, Strings) :-simple_plural(String, Strings) :-
append(String, “s”, Strings).append(String, “s”, Strings).
String AppendsString Appends
?- ?- simple_plural(“Dog”, Plural).simple_plural(“Dog”, Plural).
Plural = [68, 111, 103, 115]Plural = [68, 111, 103, 115]
YesYes
?- ?- name(dog, _D), simple_plural(_D, _Ds), name(dog, _D), simple_plural(_D, _Ds), name(Ds, _Ds).name(Ds, _Ds).
Ds = dogsDs = dogs
Yes Yes name/2 does the conversion(both directions)
ExerciseExercise
Write a predicate to pluralize words (atoms)Write a predicate to pluralize words (atoms)
End inEnd in change/addchange/add
o, s, sh, ch, x, zo, s, sh, ch, x, z add esadd esay, ey, oy, uyay, ey, oy, uy add sadd s
yy change to ieschange to iesf, fef, fe change to veschange to ves
(all others)(all others) add sadd s
class
play
ply
wolf
dog
classes
plays
plies
wolves
dogs
Solution (Part I)Solution (Part I)
Translate atoms to lists, calculate the Translate atoms to lists, calculate the correct plural, & translate plural back to correct plural, & translate plural back to atomatom
plural(Word, Words) :-plural(Word, Words) :-name(Word, Letters),name(Word, Letters),pluralize(Letters, Letterses),pluralize(Letters, Letterses),name(Words, Letterses).name(Words, Letterses).
Partial SolutionPartial Solution
pluralize(Wordo, Wordoes) :-pluralize(Wordo, Wordoes) :-
append(_, “o”, Wordo), !,append(_, “o”, Wordo), !,
append(Wordo, “es”, Wordoes).append(Wordo, “es”, Wordoes).
pluralize(Worf, Worves) :-pluralize(Worf, Worves) :-
append(Wor, “f”, Worf), !,append(Wor, “f”, Worf), !,
append(Wor, “ves”, Worves).append(Wor, “ves”, Worves).
Add escargo cargoes
Change f to veswolf wolves
ExerciseExercise
Write a predicate x_out_numbers/2Write a predicate x_out_numbers/2?- ?- x_out_numbers(‘The price was $49.99’, X).x_out_numbers(‘The price was $49.99’, X).X = ‘The price was $xx.xx’X = ‘The price was $xx.xx’YesYes– replaces each digit with an xreplaces each digit with an x– Hint: use name/2 to translate to character listHint: use name/2 to translate to character list– between(0’0, 0’9, Digit)between(0’0, 0’9, Digit)
Solution (Part 1)Solution (Part 1)
x_out_digits(S3nt3nc3, Sxntxncx) :-x_out_digits(S3nt3nc3, Sxntxncx) :-name(S3nt3nc3, Str1ng),name(S3nt3nc3, Str1ng),x_out_string_digits(Str1ng, Strxng),x_out_string_digits(Str1ng, Strxng),name(Sxntxncx, Strxng).name(Sxntxncx, Strxng).
Solution (Part 1)Solution (Part 1)
% base case% base casex_out_string_digits([], []).x_out_string_digits([], []).
% recursive special case: replace a digit% recursive special case: replace a digitx_out_string_digits([D | D1s], [x | Dxs]) :-x_out_string_digits([D | D1s], [x | Dxs]) :-
between(0’0, 0’9, D), !,between(0’0, 0’9, D), !,x_out_string_digits(D1s, Dxs).x_out_string_digits(D1s, Dxs).
% default recursive case% default recursive casex_out_string_digits([H | D1s], [H | Dxs]) :-x_out_string_digits([H | D1s], [H | Dxs]) :-
x_out_string_digits(D1s, Dxs).x_out_string_digits(D1s, Dxs).
Next TimeNext Time
Manipulating the knowledge baseManipulating the knowledge base– assertion, retractionassertion, retraction– memorizationmemorization– clausesclauses