`member` returns `NIL` 即使字符串存在于列表中

`member` returns `NIL` even though string exists in the list

普通口齿不清。

我正在尝试确定给定列表中是否存在某个字符串。

我的目标是 (member searched-string my-list) 但我一直收到 NIL.

为什么 (member "foo" '("foo" "bar")) return NIL?

因为(eql "foo" "foo") ; ==> nil。虽然 CLHS member 中没有记录,但使用 #'eql 作为标准测试。要让它使用 #'equal,它也会对显示相同

的结构计算 t
(equal "foo" "foo") ; ==> t
(member "foo" '("foo" "bar") :test #'equal) ; ==> ("foo" "bar")

字符串存储为字符向量,因此除非它是同一个对象 eqeql 将评估为 nilequal 检查是否所有字符串中的字符是 eql

注意:(eql "foo" "foo") 也可以是 t。由于它是文字,因此是常量数据,因此编译后的相同代码将在某些实现中仅存储一次 "test",以便它们变为指针相等(eq)。

:test关键字参数的默认值为#'eql:

If neither a :test nor a :test-not argument is supplied, it is as if a :test argument of #'eql was supplied.

17.2.1 Rules about Test Functions - Satisfying a Two-Argument Test

字符串既不是数字也不是字符,因此只有当两个字符串 eq(相同)时,它们才是 eql,但在您的示例中,您可能分配了两个不同的字符串。您可以在 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)