If you are sure that your list contains only strings, you can use the type-specific functions string= (case sensitive) or string-equal (case insensitive).
However, these functions also accept characters and mixtures of characters and strings.
Thus, (assoc "ABC" list :test #'string=) will find not only the key "ABC" , but also any character whose name is "ABC" , for example the character :abc or cl-use:abc or mypackage:abc .
The common equal and equalp for comparing any two objects do not have this behavior. Like the above two, equal and equalp , respectively, are case sensitive and case insensitive. However, they also compare other types of objects.
Unlike string= and string-equal , equal and equalp , strings and characters should not be considered equivalent; i.e. (equalp "FOO" 'FOO) -> nil . They also do not consider equivalent characters equivalent: (equalp 'foo :foo) -> nil . When both arguments are characters, equal and equalp apply the same test as the eq function.
Therefore, I would say that a suitable test for your associative list, since you have a mixture of string and symbolic keys, is one of two functions equal and equalp .
These functions will also allow your list to have other types of keys, such as numbers. equalp will compare numbers by value, so 1 and 1.0 will be the same key, while equal will be more stringent. Both of these functions are returned to lists. Lists (1 2) and (1 2) are equal , even if they are not the same object (separately consed), while (1 2) and (1 2.0) not equal , but equalp (if you donβt have very weird floating point system). In addition, vector objects are not compared by equal elements, but they are equalp .
Even if you only had lines in the list, itβs better to use these two functions. You will not get much, if any, performance benefits. string= is still necessary to check the types of the arguments to make sure they are supported types, and send according to what combination of string and character are the arguments. equal sends over numerous type capabilities, but this can be done efficiently.
Using overly type-specific functions or improperly strict equality is usually bad practice in Lisp.
string= used consciously, however, not to save machine cycles, but in situations where characters should be compared as strings, or a mixture of characters and strings. For example, if you are implementing a loop macro, you can use string= to define the words of the loop sentence, which according to the ANSI Common Lisp specification are considered equivalent based on the symbol name. Users can write (loop :for x below 42 ...) or (loop mypackage:for x below 42 ...) . However (loop "FOR" ...) invalid! Thus, you cannot rely only on string= ; you will need to confirm that the word clause is a symbol.