`member` возвращает` NIL`, даже если строка существует в списке - PullRequest
2 голосов
/ 08 мая 2020

Common Lisp.

Я пытаюсь определить, присутствует ли строка в данном списке.

Моя цель - получить (member searched-string my-list), но я продолжаю получать NIL.

Почему (member "foo" '("foo" "bar")) возвращает NIL?

enter image description here

Ответы [ 2 ]

8 голосов
/ 08 мая 2020

Значение по умолчанию для параметра ключевого слова :test - #'eql:

Если не указан ни аргумент :test, ни :test-not, это как если бы :test был предоставлен аргумент #'eql.

17.2.1 Правила о тестовых функциях - выполнение теста с двумя аргументами

Строки не являются числами и символами, поэтому две строки равны eql, только если они eq (идентичны), но в вашем примере у вас, вероятно, есть две разные строки. У вас может быть оптимизация, при которой string= строки интернируются компилятором, делая их eq, но это будет деталь реализации.

Здесь ниже та же строка foo используется для построения списка , и в качестве аргумента для member, и вызов фактически находит значение:

(let ((foo "foo"))
  (member foo (list foo "bar")))
=> ("foo" "bar")

Но в более общем плане вы хотите передать функцию сравнения строк, например string-equal (без учета регистра) или string= (точный регистр) или просто универсальный предикат равенства; в обоих примерах ниже находится строка sarch:

(member "foo" '("foo" "bar") :test #'equal)
(member "FOO" '("foo" "bar") :test #'equalp)
4 голосов
/ 08 мая 2020

Это потому, что (eql "foo" "foo") ; ==> nil. Хотя это не задокументировано в CLHS, member использует #'eql в качестве стандартного теста. Чтобы заставить его использовать #'equal, который также оценивает t для структур, которые отображают одинаковые

(equal "foo" "foo") ; ==> t
(member "foo" '("foo" "bar") :test #'equal) ; ==> ("foo" "bar")

Строка сохраняется как вектор символов и, следовательно, если это не тот же объект eq и eql будет оцениваться как nil, а equal проверяет, все ли символы в строках равны eql.

NB: (eql "foo" "foo") также может быть t. Поскольку это литералы и, следовательно, постоянные данные, один и тот же скомпилированный код в некоторых реализациях сохранит "test" только один раз, чтобы они стали равными по указателю (eq).

...