Search code examples
common-lispequalityclos

Why is the find function returning NIL in this case?


I am new to Common Lisp, especially CLOS. I am using the REPL inside a package called Nyxt.

Nyxt is designed to be an infinitely extensible browser. Hence, the user can change the code and/or create extensions while the program is running. This is live hackability by design. My question is unrelated to the Nyxt package, but since it happened inside the package I thought it would be be better to provide more background info.

I do not understand the behavior of the function find in this concrete case.

I have this small list of instances representing URLs:

NYXT> small-list
(#<QURI.URI.HTTP:URI-HTTPS https://duckduckgo.com/?q=google+analytics&ia=web>
 #<QURI.URI.HTTP:URI-HTTPS https://duckduckgo.com/l/?uddg=https%3A%2F%2Fanalytics.withgoogle.com%2F&notrut=duckduck_in>
 #<QURI.URI.HTTP:URI-HTTPS https://en.wikipedia.org/wiki/CAPTCHA>
 #<QURI.URI:URI about:blank> #<QURI.URI.HTTP:URI-HTTPS https://ambrevar.xyz/>)

Then, I define as a variable the third element of the list:

NYXT> (defparameter wikipedia-page (third small-list))
WIKIPEDIA-PAGE

NYXT> wikipedia-page
#<QURI.URI.HTTP:URI-HTTPS https://en.wikipedia.org/wiki/CAPTCHA>

Ok, it works as expected if I try to find the wikipedia-page inside the list:

NYXT> (find wikipedia-page small-list :test #'equal)
#<QURI.URI.HTTP:URI-HTTPS https://en.wikipedia.org/wiki/CAPTCHA>

Now, let me bound another instance to a variable:

NYXT> (defparameter blog (last small-list))
BLOG

NYXT> blog
(#<QURI.URI.HTTP:URI-HTTPS https://ambrevar.xyz/>)

The problem is when I try to find it:

NYXT> (find blog small-list :test #'equal)
NIL

Now is the strangest part ever for me, the equality test works:

NYXT> (equal blog (last small-list))
T

Could anyone help me? Why find does not work for the blog case? Is this related to CLOS and how objects should be compared?

Thanks


Solution

  • Given small-list as defined in the question, (last small-list) is the list (#<QURI.URI.HTTP:URI-HTTPS https://ambrevar.xyz/>). So, of course (find (last small-list) small-list) should be expected to return nil, since small-list does not contain the element (#<QURI.URI.HTTP:URI-HTTPS https://ambrevar.xyz/>) (which is a list); rather small-list contains the element #<QURI.URI.HTTP:URI-HTTPS https://ambrevar.xyz/>.

    Remember that last returns the last cons of a list (or the last n conses if you provide the optional argument). You could do: (find (car (last small-list)) small-list).

    Another possibility would be to use the test and key keyword arguments: (find (last small-list) small-list :test #'equal :key #'list). But, I'm not sure when I would prefer this to the first solution.