Question

I am new to Lisp and have an issue regarding recursion and function returns. In the interests of trying to better understand and solve my problem, I provide the following scenario. I apologize if it is verbose. If this aggravates others, I'm happy to trim it down. To skip right to the business, please read from the horizontal line onward.

Imagine a waitress at a bar. Instead of taking drink orders, she forces her patrons to identify themselves as drinkers of beer, rum, whiskey, or some combination of these. Then she grabs a tray full of either beer, rum or whiskey and does a lap around the bar, leaving exactly one drink with any customer who has identified themself as a drinker of that particular beverage. When she's finished each round, she always sits down and has a Long Island Ice Tea. Afterward, she proceeds to grab another tray of exclusively one type of drink and goes out for delivery again. No customer can ever refuse a drink, and no one can change their drink preferences.

Now, Mindy (the waitress) needs a novel way of keeping track of how many drinks of each type she is delivering to each patron. Mindy isn't very good at math and by the end of the night all of those Long Island Ice Teas are really adding up.

So when she asked for a simple solution for tracking her drink dispensing, I naturally suggested creating a simple little Lisp program. Here's how it is to work: When she has finished delivering a round of tasty beverages, Mindy simply walks up to her Altair 8800 and types the following:

(update-orders <order-list> <drink>)

where is the list of all customers and their orders, and is the drink she just served in her most recent outing.

It should properly go through the lists of customers and their drink counts, updating the proper drinks by one and leaving the others alone. To interface with the computer system in place, a newly-updated orders-list needs to be returned from the function when it is complete.

Just today I came across the following bug: after properly calling the function, the value returned is not what I want. The list only includes the very last drink count list of the very first customer in the list, every time. Recursive programming is the real culprit here, as opposed to Lisp, and I have tried altering the code to fix this, but to no avail. I need a full list returned from the function.


As you may have guessed, this story is not true. The real problem I am trying to solve is related to calculus, and is a well-known topic for those getting their feet wet with Lisp. However, my problem is not with my assignment, but rather with wrapping my mind around the recursive calls and returning full lists of values to calling functions, so that I may build a complete list of all terms to return when finished. After I am able to solve this sub-problem, I am just a stones throw away from applying it to my actual assignment and solving it.

Running the following function call:

(update-orders (quote ( (bill (4 beer) (5 whiskey)) (jim (1 beer)) (kenny (1 whiskey) (4 rum)) (abdul (1 beer) (3 whiskey) (2 rum) ))) (quote beer))

gets me the following returned:

((5 WHISKEY))

I would, instead, like a list in the same format as the one supplied to the function above.

Please see the code below. It has been modified to include debugging output to the screen for convenience. Function drink-list is likely where my trouble lies.

(defun update-orders (x d)
    (print 'orders)
    (prin1 x)
    (order (car x) d)
)

(defun order (x d)
    (print 'order)
    (prin1 x)
    (drink-list (cdr x) d)
)

(defun drink-list (x d)
    (print 'drink-list)
    (prin1 x)
    ;(append
    ;(cons
    ;(list
        (drink-count (car x) d)
        (cond
            ((cdr x) (drink-list (cdr x) d))
            (t x)
        )
    ;)
)

(defun drink-count (x d)
    (print 'drink-count)
    (prin1 x)
    (list
        (cond
            ((eq (car (cdr x)) d)    
                (modify-count (car x) 1))
            (t x)
        )
    )
)

(defun modify-count (x d)
    (print 'modify-count)
    (prin1 x)
    (print 'new-modify-count)
    (prin1 (+ (parse-integer (subseq (write-to-string x) 0)) 1))
    (list
        (+ (parse-integer (subseq (write-to-string x) 0)) 1)
    )
)

EDIT:

I have incorporated ooga's suggestions into my code. The new order and update-order functions are shown below:

(defun update-orders (x d)
    (cond
        ((null x) ())
        (t        (cons (order (car x) d) (update-orders (cdr x) d)))
    )
)

(defun order (x d)
    ;(print 'order)
    ;(prin1 x)
    (drink-list (cdr x) d)
)

I now get the following list returned, running the same function call as above:

(((5 WHISKEY)) ((1 BEER)) ((4 RUM)) ((2 RUM)))

which is a list of embedded lists (2 deep, I believe) that include all of the last drink item and drink count of each patron in the list (Bill's final list entry is 5 whiskey, Jim final entry is 1 beer, etc). Their first n-1 drinks are not added to the returned list of their drinks.

Have I misread your suggestion? I have a feeling I am a half step away here.

Was it helpful?

Solution

In update-orders you only pass the car of x to order. The rest of x is completely ignored. Then you only pass the cdr of that is on to drink-list.

As an example of how your code should be structured, here's a program that adds 1 to each member of the given list.

Example call: (increment-list '(1 2 3))

(defun increment-list (x)
    (cond
        ((null x) ())
        (t        (cons (increment (car x)) (increment-list (cdr x))))
    )
)

(defun increment (x)
    (+ x 1)
)

Change increment-list to update-orders and increment to orders (and add the second input, etc.) and that, I think, should be your program structure.

Also, you should try to build it from the bottom up. Try writing a function that will add one to the number if the given drink in a (number drink) list matches. I.e., given this:

(add-one-if '(4 beer) 'beer)

It should return this

(5 BEER)

And given this

(add-one-if '(3 whiskey) 'beer)

It should return this

(3 WHISKEY)

OTHER TIPS

As suggest above, here is the full code I have implemented to solve my problem, incorporating the suggested structure provided by ooga.

;;;; WAITING-TABLES

(defun update-orders (x d)
    (cond
        ((null x) ())
        (t        (cons (order (car x) d) (update-orders (cdr x) d)))
    )
)

(defun order (x d)
    (cons (car x)  (drink-list (cdr x) d))
)

(defun drink-list (x d)
    (cond
        ((null x) ())
        (t        (cons (drink-count (car x) d) (drink-list (cdr x) d)))       
    )
)

(defun drink-count (x d)
    (cond
        ((eq (car (cdr x)) d)
            (cons (modify-count (car x) 1) (drink-count (cdr x) d)))
        (t x)
    )
)

(defun modify-count (x d)
    (+ (parse-integer (subseq (write-to-string x) 0)) 1)
)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top