Если вам нужно сравнить, используя один из операторов эквивалентности построения, вы можете использовать memq
, memv
или member
, в зависимости от того, хотите ли вы найти равенство, используя eq?
, eqv?
или equal?
соответственно.
> (memq 'a '(a b c))
'(a b c)
> (memq 'b '(a b c))
'(b c)
> (memq 'x '(a b c))
#f
Как видите, эти функции возвращают подсписок, начиная с первого соответствующего элемента, если они находят элемент. Это связано с тем, что при поиске в списке, который может содержать логические значения, необходимо уметь различать случай нахождения #f
и случай не нахождения искомого элемента. Список является истинным значением (единственное ложное значение в схеме - #f
), поэтому вы можете использовать результат memq
, memv
или member
в любом контексте, ожидающем логическое значение, например if
, cond
, and
или or
выражение.
> (if (memq 'a '(a b c))
"It's there! :)"
"It's not... :(")
"It's there! :)"
В чем разница между тремя различными функциями? Он основан на том, какую функцию эквивалентности они используют для сравнения. eq?
(и, следовательно, memq
) проверяет, являются ли два объекта одним и тем же базовым объектом; это в основном эквивалентно сравнению указателя (или прямому сравнению значения в случае целых чисел). Таким образом, две строки или списки, которые выглядят одинаково, могут не быть eq?
, поскольку они хранятся в разных местах в памяти. equal?
(и, следовательно, member?
) выполняет глубокое сравнение списков и строк, и поэтому в принципе любые два элемента, которые печатают одинаково, будут equal?
. eqv?
похоже на eq?
почти для всех, кроме чисел; для чисел два числа, которые численно эквивалентны, всегда будут eqv?
, но они не могут быть eq?
(это из-за чисел и рациональных чисел, которые могут храниться таким образом, что они не будут eq?
)
> (eq? 'a 'a)
#t
> (eq? 'a 'b)
#f
> (eq? (list 'a 'b 'c) (list 'a 'b 'c))
#f
> (equal? (list 'a 'b 'c) (list 'a 'b 'c))
#t
> (eqv? (+ 1/2 1/3) (+ 1/2 1/3))
#t
(Обратите внимание, что некоторое поведение функций не определено спецификацией и, таким образом, может отличаться от реализации к реализации; я включил примеры, которые должны работать в любой R 5 RS-совместимой схеме, которая реализует точное рациональное цифры)
Если вам нужно искать элемент в списке, используя предикат эквивалентности, отличный от встроенного, то вы можете захотеть find
или find-tail
от SRFI-1:
> (find-tail? (lambda (x) (> x 3)) '(1 2 3 4 5 6))
'(4 5 6)