; exercise 7
(define (read-line . port)
(define (eat p c)
(if (and (not (eof-object? (peek-char p)))
(char=? (peek-char p) c))
(read-char p)))
(let ((p (if (null? port) (current-input-port) (car port))))
(let loop ((c (read-char p)) (line '()))
(cond ((eof-object? c) (if (null? line) c (list->string (reverse line))))
((char=? #\newline c) (eat p #\return) (list->string (reverse line)))
((char=? #\return c) (eat p #\newline) (list->string (reverse line)))
(else (loop (read-char p) (cons c line)))))))
(define (string-split sep str)
(define (f cs xs) (cons (list->string (reverse cs)) xs))
(let loop ((ss (string->list str)) (cs '()) (xs '()))
(cond ((null? ss) (reverse (if (null? cs) xs (f cs xs))))
((char=? (car ss) sep) (loop (cdr ss) '() (f cs xs)))
(else (loop (cdr ss) (cons (car ss) cs) xs)))))
(define (read-input)
(let loop ((line (read-line)) (lines (list)))
(if (eof-object? line) lines
(let* ((fields (string-split #\| line))
(student-number (string->number (car fields)))
(class-name (cadr fields))
(grade (string->number (caddr fields)))
(fields (list student-number class-name grade)))
(loop (read-line) (cons fields lines))))))
(define (lt? a b)
(or (string<? (cadr a) (cadr b))
(and (not (string<? (cadr b) (cadr a)))
(< (car a) (car b)))))
(define (write-output lines)
(let loop ((lines (sort lines lt?)) (prev ""))
(when (pair? lines)
(when (not (string=? prev (cadar lines)))
(display (cadar lines)) (display #\tab)
(display (caddar lines)) (newline))
(loop (cdr lines) (cadar lines)))))
(define (exercise7)
(write-output (read-input)))
(exercise7)