I would suggest the following:
(define (sub x y lst)
(let loop ((lst lst) (counter 0))
(cond
((null? lst)
'())
((and (>= counter x) (< counter y))
(cons (car lst) (loop (cdr lst) (+ 1 counter))))
(else
(loop (cdr lst) (+ 1 counter))))))
- no global variable, counter is local here
- you cons x, but you must cons (car lst)
Your code, rewritten, would be
(define counter 0)
(define (sub x y a_list)
(cond
((null? a_list)
'())
((and (>= counter x) (< counter y))
(begin
(set! counter (+ counter 1))
(cons (car a_list) (sub x y (cdr a_list)))))
(else
(begin
(set! counter (+ counter 1))
(sub x y (cdr a_list))))))
but the second execution would fail because the counter is not reset to 0:
(sub 1 3 '(X G H S E))
=> '(G H)
(sub 1 3 '(X G H S E))
=> '()
Regarding your initial question:
to group forms in a place where only one form is allowed (if
comes to mind), use begin
(see the excellent Racket help for details)
((f x ...) y ...)
first evaluates (f x ...)
, which should return a procedure p
; then it evaluates (p y ...)
. In your case, f
was set!
, which always evaluates to (void)
, so this was evaluated as ((void) y ...)
. Hence the error message.
EDIT
Illustrating @WorBlux's idea without a counter:
(define (sub x y lst)
(cond
((or (null? lst) (<= y 0))
'())
((> x 0)
(sub (- x 1) (- y 1) (cdr lst)))
(else
(cons (car lst) (sub (- x 1) (- y 1) (cdr lst))))))