Ваша проблема требует фолда, который является стандартным способом итерации по списку, сохраняя при этом записи о проделанной работе.
Здесь очень грубый метод, использующий для / fold :
(define (nth-filtered predicate index)
(for/fold ([count 0]
[current #f] #:result current)
([n (in-naturals 1)]) ; we start at 1 but we could start at 0
#:break (= count index)
(values (if (predicate n) (add1 count) count)
n)))
for/fold
принимает список начального состояния.Здесь мы определяем count
как количество раз, которое данный предикат возвратил #t
и current
как проверенное в данный момент значение.
Затем он принимает список итераторов, в этом случае мы повторяем только бесконечно(in-naturals)
.
Чтобы остановить его, мы предоставляем условие #:break
, когда «количество истинных предикатов (count
) равно запрошенной сумме (index
)».
for/fold
запрашивает, чтобы его тело заканчивалось списком значений для каждой переменной "состояния", чтобы обновить их для следующей итерации.Здесь мы предоставляем два значения: одно - новое count
, другое - просто текущее n
.
Вы можете попробовать его, оно работает так, как вы просили:
> (nth-filtered even? 1)
2
> (require math/number-theory)
> (nth-filtered prime? 10)
29
> (nth-filtered prime? 5)
11