Input and Output Chapter 6 Warning n There

  • Slides: 59
Download presentation
Input and Output Chapter 6

Input and Output Chapter 6

Warning n There is absolutely no need to do I/O for assignment #2 –

Warning n There is absolutely no need to do I/O for assignment #2 – all the I/O that needs to be done will be done automatically by Prolog n Still, we sometimes want a program to interact with a user in a more natural way

Simple Output write/1 writes its argument into the console n nl/0 writes a new-line

Simple Output write/1 writes its argument into the console n nl/0 writes a new-line character n – ends the current line n write_ln/1 = (write/1, nl) hello_world : write_ln(‘Hello, World!’).

Simple Input n read/1 reads a term from the console – term can be

Simple Input n read/1 reads a term from the console – term can be number/atom/list/… – end with a period – everything written just like in Prolog read_int(N) : read(N), integer(N).

Read and Write n Read a name for a student ? - read_name(100176, Student).

Read and Write n Read a name for a student ? - read_name(100176, Student). What is the name for student #100176? mark. Student = student(100176, mark) Yes

Read and Write n Read a name for a student read_name(ID, student(ID, Name)) :

Read and Write n Read a name for a student read_name(ID, student(ID, Name)) : write(‘What is the name for student #’), write(ID), write(‘? ’), read(Name). Note: SWI Prolog won’t print |: prompt if there’s already output on the line

Yes Or No? Utility predicate n Succeeds if user enters yes n Fails if

Yes Or No? Utility predicate n Succeeds if user enters yes n Fails if user enters anything else user_says_yes : write(‘Enter yes or no: ’), read(yes). n Reads a term & tries to unify it with yes. Fails if user enters anything other than yes.

Exercise n Write read_names/2 – takes a list of student IDs and reads a

Exercise n Write read_names/2 – takes a list of student IDs and reads a name for each student ID – use read_name/2 as defined above ? - read_names([10076, 20012], L). What is the name for student #10076? mark. What is the name for student #20012? cathy. L = [student(10076, mark), student(20012, cathy)] Yes

Solution % base case – no IDs read_names([], []). % recursive case: read name

Solution % base case – no IDs read_names([], []). % recursive case: read name for first ID & recur read_names([ID|IDs], [N|Ns]) : read_name(ID, N), read_names(IDs, Ns).

Reading in a Loop n “Loop” above is controlled by a list – not

Reading in a Loop n “Loop” above is controlled by a list – not really a loop, but that’s how it acts Reading a value for each element of the list n There are other common “loop” strategies n

Sentinel Controlled Loops n Keep reading until some special value – similar controls used

Sentinel Controlled Loops n Keep reading until some special value – similar controls used in imperative languages Prompt. And. Read(N); while (N SENTINEL) If reading positive numbers, SENTINEL may be 0 or – 1 Process(N); Prompt. And. Read(N); n Note structure: – read, loop(test, process, read)

Sentinels in Prolog n Similar structure – read, recur(test, process, read) – need a

Sentinels in Prolog n Similar structure – read, recur(test, process, read) – need a predicate for the recursion – need a new variable for next value – separate predicate may be used to start off n Sentinel can be anything – can be a different type than other objects read – often use atom stop as a sentinel

Generic Sentinel Code read_main : Main predicate reads first item read(N), starts “loop” running

Generic Sentinel Code read_main : Main predicate reads first item read(N), starts “loop” running read_loop(N, …). read_loop(stop, …) : - Base case – got the sentinel commit so don’t process sentinel !. read_loop(N, …) : Recursive case process the value read process(N, …), read the next value read(Next), recur read_loop(Next, …).

Sentinel Code cuber : read_number(N), cuber_loop(N). cuber_loop(stop) : !. cuber_loop(N) : print_cube(N), read_number(Next), cuber_loop(Next).

Sentinel Code cuber : read_number(N), cuber_loop(N). cuber_loop(stop) : !. cuber_loop(N) : print_cube(N), read_number(Next), cuber_loop(Next). read_number(N) : write_ln(‘Enter …’), read(N). print_cube(N) : write(‘The cube of ’), write(N), write(‘ is ’), N 3 is N^3, write_ln(N 3).

Sentinel Control Exercise n Write a sentinel controlled “loop” to read in a person’s

Sentinel Control Exercise n Write a sentinel controlled “loop” to read in a person’s name and print out their parent’s names (family_1. PL already loaded) ? - parentage. Enter the person’s name or quit: bob’s parent is pam. Enter the person’s name or quit: quit. Yes

Solution parentage : read_name(N), parentage_loop(N). parentage_loop(quit) : !. parentage_loop(N) : print_parent(N), read_name(Next), parentage_loop(Next). read_name(N)

Solution parentage : read_name(N), parentage_loop(N). parentage_loop(quit) : !. parentage_loop(N) : print_parent(N), read_name(Next), parentage_loop(Next). read_name(N) : write(‘Enter …’), read(N). print_parent(N) : parent(P, N), write(‘’s parent is ’), write(P), write(‘. nn’).

Special Characters n Note how to print a single quote: – ’ inside the

Special Characters n Note how to print a single quote: – ’ inside the single quotes – “escape sequence” n Can also print end-of-line character (n) – don’t need write_ln – just for convenience n Others as in c and Java

Checking Input n May want to check input to see if it’s valid –

Checking Input n May want to check input to see if it’s valid – number or stop for cuber – atom for parentage n This also a loop – read, loop(test, warn, read) n Can do this with a modified sentinel – stop when you get valid input

Type Testing n Can check what kind of value a variable has – atom(X)

Type Testing n Can check what kind of value a variable has – atom(X) – X’s value is an atom (not a number) – number(X), integer(X), float(X) – compound(X) – X’s value is a term n Can check whether X has a value – var(X) – X is unbound – nonvar(X) – X is bound – ground(X) – X has no variables left in it at all

Checking for Valid Input read_number_or_stop(N) : write(‘Enter a number or the word stop: ’),

Checking for Valid Input read_number_or_stop(N) : write(‘Enter a number or the word stop: ’), read(Try), read_number_test(Try, N). read_number_test(N, N) : (integer(N) ; N = stop), !. read_number_test(Try, N) : write(‘That is invalid input. Please try again: ’), read(Next), read_number_test(Next, N).

About the Solution Uses an extra predicate n Can avoid that n – put

About the Solution Uses an extra predicate n Can avoid that n – put test in read_number itself – recur on read_number n Necessary change – first read into a new variable – gets bound with N only if it’s OK

Modified Solution read_number_or_stop(N) : write(‘Enter a number or the word stop: ’), read(Input), (

Modified Solution read_number_or_stop(N) : write(‘Enter a number or the word stop: ’), read(Input), ( (integer(Input) ; Input = stop), !, N = Input ; write_ln(‘Invalid input. Please try again. ’), read_number_or_stop(N) ).

Exercise n Do the same for the read_name loop – should read an atom

Exercise n Do the same for the read_name loop – should read an atom – do not use a helper predicate read_name(N) : write(‘Enter a name or quit: ’), read(N). ? - read_name(N). Enter a name or quit: student(10076, mark). That is not a valid name. Please try again.

Solution read_name(N) : write(‘Enter a name or quit: ’), read(Input), ( atom(Input), !, N

Solution read_name(N) : write(‘Enter a name or quit: ’), read(Input), ( atom(Input), !, N = Input ; write_ln(‘Invalid input. Please try again. ’), read_name(N) ).

File Input/Output Above does input/output at console n Can also read from/write to files

File Input/Output Above does input/output at console n Can also read from/write to files n Use the same predicates n – read/1, write/1 n Just need to indicate that I/O should be from/to a given file

File Input Tell Prolog to look in a given file n Predicate is called

File Input Tell Prolog to look in a given file n Predicate is called “see” n – not “look” or “look_at” ? - see(‘data. txt’), read(File. Item). File. Item = data_item(1) Yes % data. txt % (read skips comments) data_item(1). data_item(2). another_item. and_another. 30.

See Persists Prolog will continue to “see” the file until you say otherwise n

See Persists Prolog will continue to “see” the file until you say otherwise n Say otherwise by using seen/0 n ? - read(FI 2), seen, read(N). |: from_console. Prolog returns to where it was FI 2 = data_item(2) reading from before N = from_console here the console but could be another file Yes

File Output n Use tell/1 and told/0 – just like see/1 and seen/0 ?

File Output n Use tell/1 and told/0 – just like see/1 and seen/0 ? - tell(‘outfile. txt’), write(fred), told. Yes n Note: does not automatically add periods – if you want to make a Prolog readable file, you must add the periods yourself – …, write(fred), write_ln(‘. ’), …

End of File n What if there’s no file there to read? – File

End of File n What if there’s no file there to read? – File doesn’t exist ERROR n What if it’s empty or you’ve read it all? – read succeeds(!) – binds argument to atom end_of_file – use sentinel controlled loop

Exercise n Write a loop to read and print every term from a given

Exercise n Write a loop to read and print every term from a given file – one term per line – switch back to regular input when done ? - show_terms(‘data. txt’). data_item(1) data_item(2) …

Solution show_terms(File) : No need to prompt for input see(File), it’s a file read(N),

Solution show_terms(File) : No need to prompt for input see(File), it’s a file read(N), show_term_loop(N), seen. show_term_loop(end_of_file) : - !. show_term_loop(N) : write_ln(N), read(Next), show_term_loop(Next).

Going Back to the Console n seen & told will return to previous file

Going Back to the Console n seen & told will return to previous file – to console if there was no previous file n What if want to switch temporarily to console & then resume the file? – special argument: the atom user – see(user), tell(user), …, seen, told.

Exercise n Modify show_term_loop/1 to pause if it reads the atom stop – it

Exercise n Modify show_term_loop/1 to pause if it reads the atom stop – it should ask the user whether it should continue – continues only if user answers yes – bonus – make sure file gets closed even if the user says not to continue (i. e. succeed even if user says not to continue reading)

New Rule nd (2 Position) show_term_loop(stop) : write_ln(‘Stop encountered!’), write(‘Continue (yes or no)? ’),

New Rule nd (2 Position) show_term_loop(stop) : write_ln(‘Stop encountered!’), write(‘Continue (yes or no)? ’), see(user), read(Response), seen, ( Response=yes, !, read(N), show_term_loop(N) ; true May also want to tell(user), …, told Just in case user has directed output to a file ).

Character I/O and Strings Chapter 6

Character I/O and Strings Chapter 6

Character Input/Output n Above requires files to have terms in them – that’s not

Character Input/Output n Above requires files to have terms in them – that’s not always the case Can also do input/output at character level n Use get 0/1 and get/1 to read a character n – get 0/1 gets very next character – get/1 skips white-space (gets next non-blank) n Use put/1 to write a character

Reading a Character ? - get(C). |: a C = 97 Yes n Prolog

Reading a Character ? - get(C). |: a C = 97 Yes n Prolog uses ASCII for characters – 97 is the ASCII code of the lowercase A n It’ll print an a if you put(97).

Getting a Space ? - get 0(C). |: C = 32 Yes ? -

Getting a Space ? - get 0(C). |: C = 32 Yes ? - get 0(C). |: C = 10 Yes n Type space followed by return/enter Type just return/enter get 0/1 can also get regular characters

End of File n Try to get/1 or get 0/1 past end of file

End of File n Try to get/1 or get 0/1 past end of file – returns – 1 ? - get 0(C). |: C = – 1 Yes Type ^D (control-D) or ^Z

Converting To/From ASCII n Can use 0’a to generate ASCII for a – zero,

Converting To/From ASCII n Can use 0’a to generate ASCII for a – zero, single quote, single printable character ? - X = 0’a. X = 97 n Works for other characters, too – slight problems with command line entry ? - X = (0’ ). X = 32

Squeezer Program n Read a line of characters – compress multiple spaces into just

Squeezer Program n Read a line of characters – compress multiple spaces into just one – stop when read a period squeeze_loop(0'. ) : % period 0’. = 46 !, % commit but who cares? put(0'. ). % print it squeeze_loop(0' ) : % space 0’ = 32 …

More Squeezer squeeze_loop(0' ) : % space !, % commit put(0’ ), % print

More Squeezer squeeze_loop(0' ) : % space !, % commit put(0’ ), % print it get(C), % read next non-space squeeze_loop(C). % continue squeeze_loop(A) : -% other put(A), % print it get 0(C), % read next char (maybe blank) squeeze_loop(C). % continue

Exercise n Write a predicate read_sentence/1 that reads characters up to the next period

Exercise n Write a predicate read_sentence/1 that reads characters up to the next period – stores list of characters read in its argument ? - read_sentence(L). |: OK. ASCII codes: L = [79, 75] Capital 0 is 79 Capital K is 75 Period (46) not kept

Solution read_sentence(L) : get(C), sentence_loop(C, L). sentence_loop(0’. , []) : !. sentence_loop(A, [A|T]) :

Solution read_sentence(L) : get(C), sentence_loop(C, L). sentence_loop(0’. , []) : !. sentence_loop(A, [A|T]) : get 0(C), sentence_loop(C, T). Get first character and start loop Sentinel period dropped Keep other letters and continue

Converting To/From ASCII n char_code/2 does conversion ? - char_code(a, ASCII). ASCII = 97

Converting To/From ASCII n char_code/2 does conversion ? - char_code(a, ASCII). ASCII = 97 ? - char_code(L, 32). L=‘’ ? - char_code(L, 10). L = ‘n’

Atoms & ASCII Conversion n name/2 converts atoms to their ASCII codes – and

Atoms & ASCII Conversion n name/2 converts atoms to their ASCII codes – and vice versa n Read a sentence and convert it to an atom ? - read_sentence(L), name(A, L). |: This is a sentence – soon an atom. L = [84, 105, 115, 32, 97|. . . ] A = ‘This is a sentence – soon an atom’

Exercise n Write a predicate read_word/1 that reads a single word – a word

Exercise n Write a predicate read_word/1 that reads a single word – a word is any sequence of letters terminated by anything other than a letter n You will need a predicate is_letter/1 that succeeds if its argument is a(n ASCII) letter – letters are between 0’a and 0’z or 0’A and 0’Z – write this predicate, too

Solution read_word(W) : is_letter(C) : get(C), between(0'A, 0'Z, C). read_word_loop(C, L), is_letter(C) : name(W,

Solution read_word(W) : is_letter(C) : get(C), between(0'A, 0'Z, C). read_word_loop(C, L), is_letter(C) : name(W, L). between(0'a, 0'z, C). read_word_loop(C, [C|L]) : Base at end is_letter(C), !, C is known get 0(Next), no chance infinite rec. read_word_loop(Next, L). Use get 0 instead of get read_word_loop(C, []). don’t skip spaces

String Manipulation “Prolog” = [80, 114, 111, 108, 111, 103]

String Manipulation “Prolog” = [80, 114, 111, 108, 111, 103]

Strings n Double-quoted strings are lists of characters – each character an ASCII code

Strings n Double-quoted strings are lists of characters – each character an ASCII code ? - X = “String”. Strings in double-quotes X = [83, 116, 114, 105, 110, 103] n Can get strings to print as strings ? - _X = “String”, string_to_list(S, _X). S = “String”

String Manipulation Treat strings as lists n Append a useful predicate n – append

String Manipulation Treat strings as lists n Append a useful predicate n – append one string/list to another – take strings apart simple_plural(String, Strings) : append(String, “s”, Strings).

String Appends ? - simple_plural(“Dog”, Plural). Plural = [68, 111, 103, 115] Yes ?

String Appends ? - simple_plural(“Dog”, Plural). Plural = [68, 111, 103, 115] Yes ? - name(dog, _D), simple_plural(_D, _Ds), name(Ds, _Ds). Ds = dogs name/2 does the conversion Yes (both directions)

Exercise Write a predicate to pluralize words (atoms) End in change/add class o, s,

Exercise Write a predicate to pluralize words (atoms) End in change/add class o, s, sh, ch, x, z add es classes plays ay, ey, oy, uy add s ply plies y change to ies wolf wolves f, fe change to ves dogs (all others) add s n

Solution (Part I) n Translate atoms to lists, calculate the correct plural, & translate

Solution (Part I) n Translate atoms to lists, calculate the correct plural, & translate plural back to atom plural(Word, Words) : name(Word, Letters), pluralize(Letters, Letterses), name(Words, Letterses).

Partial Solution pluralize(Wordo, Wordoes) : Add es cargoes append(_, “o”, Wordo), !, append(Wordo, “es”,

Partial Solution pluralize(Wordo, Wordoes) : Add es cargoes append(_, “o”, Wordo), !, append(Wordo, “es”, Wordoes). pluralize(Worf, Worves) : Change f to ves wolf wolves append(Wor, “f”, Worf), !, append(Wor, “ves”, Worves).

Exercise n Write a predicate x_out_numbers/2 ? - x_out_numbers(‘The price was $49. 99’, X).

Exercise n Write a predicate x_out_numbers/2 ? - x_out_numbers(‘The price was $49. 99’, X). X = ‘The price was $xx. xx’ Yes – replaces each digit with an x – Hint: use name/2 to translate to character list – between(0’ 0, 0’ 9, Digit)

Solution (Part 1) x_out_digits(S 3 nt 3 nc 3, Sxntxncx) : name(S 3 nt

Solution (Part 1) x_out_digits(S 3 nt 3 nc 3, Sxntxncx) : name(S 3 nt 3 nc 3, Str 1 ng), x_out_string_digits(Str 1 ng, Strxng), name(Sxntxncx, Strxng).

Solution (Part 1) % base case x_out_string_digits([], []). % recursive special case: replace a

Solution (Part 1) % base case x_out_string_digits([], []). % recursive special case: replace a digit x_out_string_digits([D | D 1 s], [x | Dxs]) : between(0’ 0, 0’ 9, D), !, x_out_string_digits(D 1 s, Dxs). % default recursive case x_out_string_digits([H | D 1 s], [H | Dxs]) : x_out_string_digits(D 1 s, Dxs).

Next Time n Manipulating the knowledge base – assertion, retraction – memorization – clauses

Next Time n Manipulating the knowledge base – assertion, retraction – memorization – clauses