Chapter 3

Started by
13 comments, last by pshin05 14 years ago
Quote:Original post by GameDev Doctor
Time to get feedback on 3.17 to 3.19, and confirm that my answer to 3.19 is indeed in constant space.
*** Source Snippet Removed ***
The implementation of count-pairs is a bit wierd, with the lambda at the end, but I had trouble making items reset in subsequent calls.


Exercise 3.17

You can write your count-pairs like this if you want to get rid of the weird lambda at the end.
(define (count-pairs x)  (let ((items '()))    (define (count x)      (if (or (not (pair? x))              (initems? x items))          0          (begin            (set! items (cons x items))            (+ 1               (count (car x))               (count (cdr x))))))    (set! items '())    (count x)))

A define can hold multiple expressions, as can a lambda, thus no need for begin there. Also, don't be afraid to use multiple lines.

I must admit I don't like this solution very much. It's half imperative, half not-tail-recursive functional. Try to make it fully functional and tail recursive.

Another important aspect about functional programming is recognizing patterns in your code. Now, in that specific exercise, no patterns occur. But if you take all exercises you've made so far, you must have noticed that a general (some? pred lst) function, taking a predicate and checking if any element in lst makes it return #t, might come in handy. Otherwise you'll end writing the same kind of conds over and over again. See my other thread (titled Map, Reduce and Co. IIRC) for more such helper functions.

(define (some? pred lst)  (and (not (null? lst))       (or (pred (car lst))           (some? pred (cdr lst)))))(define (member? item lst)  (some? (lambda (x)           (eq? x item))         lst))(define (count-pairs lst)  (define (count-pairs todo done acc)    (if (null? todo)        acc        (let ((current (car todo))              (rest (cdr todo)))          (if (or (not (pair? current))                  (member? current done))              (count-pairs rest done acc)              (count-pairs (append (list (car current)                                         (cdr current))                                   (cdr todo))                           (cons current done)                           (+ acc 1))))))  (count-pairs (list lst) () 0))
Advertisement
Quote:Original post by GameDev Doctor
Time to get feedback on 3.17 to 3.19, and confirm that my answer to 3.19 is indeed in constant space.
*** Source Snippet Removed ***
The implementation of count-pairs is a bit wierd, with the lambda at the end, but I had trouble making items reset in subsequent calls.


Exercise 3.18
(define cycle '((a) b c))(set-cdr! (car cycle) cycle)

Your is-cycle? returns #f.
EDIT: never mind, you only need to find cycles created by successive cdrs. Your solution works then.

If you want, you can also make your code a bit shorter using and and or instead of cond.

 (define (cycle? lst)  (define (cycle? lst done)    (and (pair? lst)         (or (member? (car lst) done)             (cycle? (car lst)                     (cons (car lst) done))             (cycle? (cdr lst)                     (cons (cdr lst) done)))))   (cycle? lst ()))


[Edited by - SamLowry on August 4, 2007 3:25:18 AM]
Quote:Original post by GameDev Doctor
Time to get feedback on 3.17 to 3.19, and confirm that my answer to 3.19 is indeed in constant space.
*** Source Snippet Removed ***
The implementation of count-pairs is a bit wierd, with the lambda at the end, but I had trouble making items reset in subsequent calls.

For 3.19, the algorithm takes increasing chunks of the list, checking if each part of that chunk is eq? to the last member of that chunk until it can verify that the list is or is not a cycle. (it does not, of course, check car, just cdr)


Exercise 3.19
AFAIK, it is constant space. You don't accumulate anything yourself and everything is tail-recursive. Maybe it's not constant space because you're using an integer which can grow large with large inputs. I'm not sure if this does break the constant space property.

There's another (simpler) way of doing it:
(define (cycle? lst)  (define (cycle? x y)    (and (pair? x)         (pair? (cdr x))         (pair? y)         (or (eq? x y)             (cycle? (cddr x)                     (cdr y)))))  (cycle? lst (cdr lst)))
Thanks, I'm resuming this after a long break, so maybe I'll try doing them again in a more functional manner, just to get back into shape.
I mean, why would you get your medical advice anywhere else?
I don't think SamLowry's solution to Exercise 3.19 is correct.

A cycle constructed as below, for example, is not properly detected.

(define a-cycle '((a . #f) b))
(set-cdr! (car a-cycle) (car a-cycle))

(cycle? a-cycle) ; this should return #t

This topic is closed to new replies.

Advertisement