0

The following is the sample code i downloaded for the problem: A counter increments by one, modify it for passing as argument the value used for incrementing. E.g.,

(let ((c (create-counter))) (+ (c) (c) (c) (c))) => 6
(let ((c (create-counter 2))) (+ (c) (c) (c) (c))) => 12

Source code:

(define create-counter
 (lambda ([num '()]) 
   (let ((temp (lambda (incr)  
           (let* ((start (- incr))
                (count start))
           (lambda num
             (set! count (+ incr count)) count)))))
       (if (null? num)
         (temp 1)
         (temp num)))))

This is my own code:

(define create-counter
      (let ([count 0])
        (lambda ([x '()])
      (cond
        [(null? x) (set! count (+ 1 count)) (- count 1)]
        [(> x 0)(set! count (+ x count)) (- count x)])
      )))

I understand a bit briefly about let and lambda as for closures handle and such. However, for this extreme problem, i still have no idea how to write like the sample code. My code does the job to calculate with following example:

(+ (create-counter 2) (create-counter 2) (create-counter 2) (create-counter 2)) -> 12

However my code does not work with sample test cases. I sometimes get 0 or errors.

What would I have to modify my source code to able to run and work as the sample? Please help me to understand better in this scope and closures thingy and any tips would be very appreciate. Thank you and sorry for my bad english.

kp2349
  • 107
  • 1
  • 14

1 Answers1

1

The code you downloaded is unnecessarily complicated.

Yours is better, but there's a confusion as to who gets the parameter which specifies the increment. create-counter is a procedure that returns a procedure, but it's the first one you want to give the parameter to, not the second.

Also, why work with a default value of '() when you can use a default value of 1? So your code becomes:

(define (create-counter (x 1))
  (let ([count 0])
    (lambda ()
      (set! count (+ x count))
      (- count x))))

By the way... instead of adding x and subtracting x again, you could just put the initial value of count into a temporary variable and return that, or just use begin0:

(define (create-counter (incr 1))
  (let ((val 0))
    (lambda ()
      (begin0
        val
        (set! val (+ val incr))))))

or even shorter and with an option to set the initial value to something else than 0:

(define (create-counter (incr 1) (val 0))
  (lambda ()
    (begin0
      val
      (set! val (+ val incr)))))

Testing:

> (let ((c (create-counter))) (+ (c) (c) (c) (c))) ; => 6
6
> (let ((c (create-counter 2))) (+ (c) (c) (c) (c))) ; => 12
12

But this does not work for

(+ (create-counter 2) (create-counter 2) (create-counter 2) (create-counter 2)) ; -> 12

since here you expect create-counter to return a numeric value, when indeed it returns a procedure.

uselpa
  • 18,732
  • 2
  • 34
  • 52
  • is there an equivalent code for the "begin0"? With lambda() i can always return the value of the function into the closure that my function has define is that correct? – kp2349 Mar 10 '16 at 02:58
  • the reason `begin0` is used is to return the current value of the counter and then iterate it afterward. If you don't want to use `begin0`, it would look like this `(λ () (let ((x val)) (set! val (+ val incr)) x))` – Mulan Mar 10 '16 at 03:14
  • thanks alot for explain to me in details. I understood the problem now. – kp2349 Mar 10 '16 at 03:36