CS 410 Programming Assignment 2

The Eliza program by Wiezenbaum is called a “psychiatrist” program, although it is actually more like what we’d call a “psychologist” program that the user can have a conversation with. This assignment will be to write a Scheme program that the user can have a conversation with. You may choose any type of consultant (e.g. psychologist, student advisor, career advisor, etc.) to give a theme to the subjects that it’s able to discuss.

It is expected that the program will give sensible replies some of the time and silly replies some of the time. In other words, the program must handle some range of user input reasonably, but may give nonsense replies – or something like “I don’t understand you.” – if the user input doesn’t match anything it expects.

Requirements:

  • Save your functions in a source file called scm
  • Your “main program” must be a function with no parameters.
  • Include a comment at the top of your program with the following information:
    • Your name, student ID, and the assignment number.
    • The name of the function that is your “main program” (in other words, how to run your program).
    • One example of input from the user in response to the program’s initial question likely to result in a “normal” reply by the program.
  • When the program starts, display a welcome message that includes what type of consultant it is and initiates the conversation (e.g. “Welcome to the student advisor. Have you selected a major yet?”)
  • Keep side effects to a minimum, and do suitable processing/error checking on the input (such as removing punctuation before trying to match the user input).
  • Some of the responses must have the ability to vary randomly (even if just between two options), i.e. the same input mustn’t always result in the same behavior.

Hints:

  • The main program can have a structure similar to:

(define student-advisor

(lambda ()

(define repeat

(lambda ()

(let ((input (read-list)))

(if (not (equal? input ’(exit)))

(begin

(displayln (respond-to-input input))

(repeat))

(display "Thanks for using the student advisor. Goodbye!\n\n")))))

(set! *random-state* (random-state-from-platform))

(display "\nWelcome to the student advisor!\n")

(display "(To leave the conversation at any time, enter EXIT)\n\n")

(displayln "Have you selected a major yet?")

(let ((input (read-list)))

(cond ((equal? ’() input)

(displayln "Please enter your response."))

((not (equal? input ’(exit)))

(displayln (respond-to-input input)))

(else (display "Hope you can reschedule your appointment soon. Goodbye!.\n\n"))) (cond ((not (equal? input ’(exit))) (repeat))))))

You are not required to use this structure for your main program – it is just provided in case you’re wondering how to get started. Some functions called above are provided below. The respond-to-input function is one that you would need to write yourself, which would match input against a list of patterns and if it finds a match, return a response for that match, or if it doesn’t find a match return a response for that case.

  • This type of program makes significant use of pattern matching. The match function from class may be useful for this, and actually provides sufficient pattern matching ability for a basic version of the program meeting the requirements above. For the optional enhancements listed below, this match function can be modified to return a list of values that matched each wildcard, rather than simply returning true or false.
  • It is useful to have a list of “rules” where each rule contains a pattern, followed by possible responses to user input matching that pattern. For example:

(define response-rules

’((()

(Please enter your response.))

((* hello *)

(Nice to meet you.)

(What is your name?))

((* computer science *)

(Have you taken the necessary math courses?)

(When are you planning to graduate?)

(Are you more interested in software or hardware?))

((* engineering *)

(What are your plans for your senior design project?)

(What about engineering interests you?)

(What type of engineering work would you like to do?))

((* computers *)

(Is that based on your own interest or because you feel required to?)

(What interests you about computers?))

((* i don’t know *)

(Do you think there’s some way to find out?))

((* you don’t know *)

(That is probably true.)

(Please tell me about %2.))

((* if *)

(Do you think its likely that %2?)

(Do you wish that %2?)

(What do you think about %2?))

((* can you help *)

(I may have some ideas if you can give me more details about your question.)

(I will try to think of some ideas.))

((* i want *)

(Do you think %2 will help?)

(How will that help you?))))

As can be seen, this is a list of lists where each sub-list is a rule, and each rule consists of a first element which is a pattern, followed by additional elements which are possible responses to input matching that pattern. So, the respond-to-input function referred to above would use the match function together with a list of rules something like this. You would need to customize the content to your selected subject of conversation, and would need quite a lot more rules than shown here for the conversations to be interesting.

  • Other useful functions from class include remove-punctuation, replace-with-space, pick and the following ones which you may use or modify as you like:

; Display parameter followed by newline followed by prompt for user input (define (displayln x)

(display x)

(newline)

(display ">> ")))

; Returns text entered by user as list of symbols with

; punctuation removed, and everything converted to lowercase.

(define read-list

(lambda ()

(let ((list-of-strings

(string-tokenize (string-downcase (remove-punctuation (readline))))))

(map string->symbol list-of-strings))))

; Return the string formed by appending each of the strings ; in the parameter together, with spaces between them.

(define make-string-with-spaces

(lambda (lst-of-strs)

(if (null? lst-of-strs)

""

(string-append (car lst-of-strs)

" "

(make-string-with-spaces (cdr lst-of-strs))))))

; Return the string formed from a list of symbols by converting

; each symbol to a string and adding spaces between them

(define list-of-symbols->string

(lambda (lst)

(make-string-with-spaces (map symbol->string lst))))

; Return the list which has the elements from its parameter, but all at

; the top level rather than in sub-lists

(define (flatten lst)

(cond ((null? lst) ’())

((list? (car lst)) (append (flatten (car lst)) (flatten (cdr lst))))

(else (append (list (car lst)) (flatten (cdr lst))))))

You may use any functions from class or the above list without reference. If you use functions from other sources that you didn’t write yourself, a reference must be given for them (in a comment).

  • Don’t try to write the program by looking at the functions provided here and trying to piece them together (would likely lead to confusion). Instead, start with getting a small fragment of the functionality working, then gradually add to it, all the while having a working program that does something. During this process, as you need various kinds of processing, check if one of the functions given here, or a built-in function, provides it.

Options:

If you have met the basic requirements and would like to enhance your program, some options are:

  • The program may include some responses that are built from parts of the user’s input. This can be achieved by modifying the match function to return a list of values from the user’s input that matched each wildcard in the pattern, then using these values to substitute for parts of the response. An example of rules that can be used for this is shown towards the end of the response-rules above – a response containing %2 means that the second element of the wildcard matches must be substituted for the %2.
  • A further enhancement would be to handle the meaning of certain word pairs such as you/me, you/I, and your/my. For example, if the user had entered “if you can help me” and this were matched by the rule above and given the response “Do you think its likely that %2?”, which after substitution became “Do you think its likely that you can help me?”, then the meaning would have been reversed. To handle this meaning, a better response would be “Do you think its likely that I can help you?”

Some questions to think about:

  • What features of your program would lead a user to believe that they are talking to a program that doesn’t really understand them, rather than to a person?
  • How is this type of program different from one that involves yes-no questions and some type of decision tree? Do you think there is any way that the two approaches might be combined?

Reminder:

  • Carefully test your program.
  • You are welcome to write your program at home. If you do, it is recommended to test it in the lab before submitting it.

How to submit your program:

  • Submit the file conversation.scm electronically by the following command:

cs410/bin/handin 2 conversation.scm

The first parameter to the handin program (“2”) is the assignment number, and the second parameter (“conversation.scm”) is the file name.