Суть в том, что если вы хорошо знаете filter
и map
, то вы можете объяснить filter-map
таким образом.Если вы не знаете, что делают filter
и map
, это не поможет вам понять это.Когда вам нужно узнать что-то новое, вам часто нужно использовать предыдущий опыт.Например.Я могу объяснить умножение, сказав, что 3 * 4
совпадает с 3 + 3 + 3 + 3
, но это не поможет, если вы не знаете, что такое +
.
В чем разница между filter
и filter-map
(filter odd? '(1 2 3 4 5)) ; ==> (1 3 5)
(filter-map odd? '(1 2 3 4 5)) ; ==> (#t #t #t))
Первое собирает исходные значения из списка, когда предикат становится правдивым.В этом случае (odd? 1)
имеет значение true и, таким образом, 1
является элементом в результате.
filter-map
не фильтрует odd?
, работает так, как будто вы передали odd?
map
.Там вы получите новый список с результатами.
(map odd? '(1 2 3 4 5)) ; ==> (#t #f #t #f #t #f)
Затем он удаляет ложные значения, чтобы у вас остались только истинные значения:
(filter identity (map odd? '(1 2 3 4 5))) ; ==> (#t #t #t)
Сейчас.Важно понимать, что в Схеме каждое значение, кроме #f
, истинно.(lambda (x) x)
- это функция идентификации, такая же, как identity
в #lang racket
.Он возвращает свой собственный аргумент.
(filter identity '(1 #f 2 #f 3)) ; ==> (1 2 3)
count
работает так же, как filter-map
, за исключением того, что возвращает только то количество элементов, которое у вас было бы.Таким образом:
(count odd? '(1 2 3 4 5)) ; ==> 3
Теперь упоминается, что это то же самое, что и:
(length (filter identity (map odd? '(1 2 3 4 5)))
За исключением того, что в коде используются map
, filter
и length
так создается 2 списка.Таким образом, пока count делает то же самое, он делает это без использования map
и filter
.Теперь кажется, что это примитив, но вы можете сделать это так:
(define (count fn lst)
(let loop ((lst lst) (cnt 0))
(cond ((null? lst) cnt)
((fn (car lst)) (loop (cdr lst) (add1 cnt)))
(else (loop (cdr lst) cnt))))