5

I am currently reading the book "Realm Of Racket", which I really like so far. However, in chapter 4 1/2, on page 74, there is one code example that I just don't get. Maybe my mind refuses to figure it out because I am on vacation, however, I simply don't get what it does.

(define (winners lst pred)
  (cond
    [(empty? lst) (list pred)]
    [else
      (define fst (first lst))
      (if (score> (record-score pred) (record-score fst))
        (list pred)
        (cons pred (winners (rest lst) fst)))]))

They don't really explain it in the book. They give some hints, though:

  • "The purpose of the function is to pick the first-place finishers from a list of game records."
  • "We have a struct definition of the following shape: (struct record (name score))"
  • "lst is a list of such records, and pred is one such record. Indeed, the original list is (cons pred lst), and it is sorted according to score."
  • "You understand that winners is a list-eating function and goes through one record at a time. When there is at least one other record, it picks the first one, names it fst, and compares the scores of fst and its predecessors. Depending on the outcome, all winning records have been picked off or winners has to continue the search for equal-scoring players."

I suppose that score> is a typo. Besides that I fully understand the code - in terms of syntax and semantics. I just don't get the practical use of that. What is this and why would somebody want that?

Will Ness
  • 70,110
  • 9
  • 98
  • 181
typeduke
  • 6,494
  • 6
  • 25
  • 34

2 Answers2

5

Unfortunately the code you are displaying is just to show you how local definitions work. In the same example you also see (define sorted-lst (sort lst ...)) which won't work at all.

Here is the whole example code from page 75, which has all the parts of page 74 in it:

(define (winning-players lst)
  (define sorted-lst (sort lst ...)) ;; local variable 
  (define (winners lst pred)         ;; locally defined procedure
    (cond
      [(empty? lst) (list pred)]
      [else
       (define fst (first lst))
       (if (score> (record-score pred) (record-score fst))           
           (list pred)           
           (cons pred (winners (rest lst) fst)))]))
  ;; START HERE:
  ;; uses both local variable and the locally defined procedure
  (winners (rest sorted-lst) (first sorted-lst))) 

What they tried to show in the following code is that outside winning-players you cannot access sorted-list nor use the procedure winners since it's hidden in winning-players' scope.

Eg. if you try to use (winners ...) in racket interactions windows you get:

winners: undefined; cannot reference undefined identifier

If you understood that you can continue to the fun in chapter 5 :)

Bundled with racket you have all the code from the code from the book under racket/collects/realm. There are 2 defintions of procedures called winners. The first in chapter 10 and the second in chapter 12.

As for the answer to what the code does. There is errors in the code so we need to fix that. My guess is that score> compares the scores of two records. I'm guessing it's supposed to be like this:

(struct record (name score) #:transparent)
(define (winning-players lst)
  (define (score> e1 e2)  ; defines a new local procedure
    (> (record-score e1)  ; that compares two records 
       (record-score e2)))

  ;; define sorted-list to be lst sorted by score in decreasing order
  (define sorted-lst (sort lst score>))  
  ;; procedure winners reduces the list to the elements 
  ;; that have same score as pred
  (define (winners lst pred)            
    (cond
      [(empty? lst) (list pred)]
      [else
       (define fst (first lst))
       (if (score> pred fst)           ;; changed to work with records
           (list pred)           
           (cons pred (winners (rest lst) fst)))]))
  ;; START HERE:
  ;; uses both local variable and the locally defined procedure
  (winners (rest sorted-lst) (first sorted-lst))) 

(define scores (list (record "John" 10) 
                     (record "Ben" 5) 
                     (record "Mary" 10) 
                     (record "Owen" 2)))  

(winning-players scores) 
; ==> (list (record "John" 10) (record "Mary" 10))

It returns a list of all the ones with the highest score.

Sylwester
  • 47,942
  • 4
  • 47
  • 79
  • I don't see what does it matter whether it's internal definition or not. The OP posted the code and asked what it does. As to why this code `(sort lst ...)` is written that way, maybe it's to cause a reader to *think*, in *which* order should the list be sorted. – Will Ness Jul 21 '13 at 23:26
  • @WillNess The code was broken. The purpose of that section of the book is to explain how define works within a procedure. Anyway, since you did point out I didn't actually answer I made an effort to try getting the code working and added that. It seems I agree with your conclusion :) – Sylwester Jul 22 '13 at 00:04
  • Why "broken"? `winners` is fully &correctly defined. The `sort`-calling form is missing just one ingredient, the comparison predicate. Also, it's obviously the intent of the author(s) that `score>` compares *scores of records*, not *records*, no need to change that. With the definition `(struct record (name score))` most probably the accessor functions are automatically defined: `record-name` and `record-score`. But "scores" presumably don't *have* to be numeric or the authors just wanted to preserve the generality of the code. Plus they get to redefine it easily, e.g. `(define score> <)`. :) – Will Ness Jul 22 '13 at 07:28
  • @WillNess the struct supplies the accessors. The comparison predicate need to be something similar to what I added since you are comparing records. They couldn't use lambda since it's not due until chapter 7. If i had something that compared records already I would reused it. I'm just guessing of course since the example is incomplete and in the book *the chapter is about how you can define things locally and nothing else*. – Sylwester Jul 22 '13 at 11:08
  • clearly `score>` in `(score> (record-score pred) (record-score fst))` compares records' scores. If you mean they couldn't use `lambda` in `(sort lst ...)`, then OK, that's why they put `...` *there*. You could've added another internal definition in its stead, without re-writing `winners` at all, too. :) -- So you were talking about whole code as in the book; I was talking about the (partial) code that the OP showed. *That's* the misunderstanding. – Will Ness Jul 22 '13 at 11:56
  • @WillNess You are right. One could make another comparison function to use solely in sort, but none of us would have written winners without reusing it. I happen to have the book and I think it's an error not to have working code samples. – Sylwester Jul 22 '13 at 12:13
4
(winners (cdr lst) (car lst))

produces the non-decreasing streak of records in lst. pred stands for "predecessor" (in the list). I assume score> is a procedure which compares scores of records (i.e. record-score seems to produce score of a record, and score> compares these scores).

IOW for a given list lst its prefix is produced such that the scores of record entries in it are in non-decreasing order.

The description states that the list is sorted before winners is applied. This only makes sense if it is sorted in decreasing order of record's score. Than that non-decreasing prefix of a decreasing list will actually contain records all with equal score - the maximal one. The "winners".

The precondition of the list being sorted in non-increasing order should have been stated much more clearly and prominently there.

Will Ness
  • 70,110
  • 9
  • 98
  • 181