Here's one possible way. The trick is to pass as an accumulator a list with two values: the first one is a flag telling you if you've found the element, and the second one keeps track of the current index, that we increment with each iteration. The flag is required because we need a way to say: stop looking for the index, we've already found it. Anyway foldl
will have to consume the whole input list, because that's how it works.
(define (my-list-ref lst n)
(let ((result
(foldl (lambda (ele acc)
(cond ((first acc) acc)
((= n (second acc)) (list #t ele))
(else (list #f (add1 (second acc))))))
(list #f 0)
lst)))
(if (first result)
(second result)
(error "index out of bounds"))))
Some tests:
(my-list-ref '(a b c) 0)
=> 'a
(my-list-ref '(a b c) 1)
=> 'b
(my-list-ref '(a b c) 2)
=> 'c
(my-list-ref '() 0)
=> index out of bounds
(my-list-ref '(a b c) -1)
=> index out of bounds
(my-list-ref '(a b c) 3)
=> index out of bounds