2

I have a table list:

(defvar moo '((:name "vince" :age 35)
              (:name "jess" :age 30)))

and I call this function on that list:

(defun test (name)
  (remove-if-not
   #'(lambda (person) (equal (getf person :name) name))
   moo))

(test "vince") ;; function call
;; => ((:name "vince" :age 35))

In the lambda function, how does the (person) parameter get filled? person is also used in the getf but I'm not sure how it's being discovered in the first place if I am only supplying the name in the test function.

What am I missing?

Will Ness
  • 70,110
  • 9
  • 98
  • 181
Vinn
  • 1,030
  • 5
  • 13

2 Answers2

2

CLHS for Function ... REMOVE-IF-NOT ... says:

remove-if-not test sequence &key from-end start end count key => result-sequence
...
...
remove-if-not return[s] a sequence from which the elements that satisfy the test have been removed.

And further it says (paraphrasing):

satisfy the test: for an element el of seq in the call (remove-if-not test seq :key key), whenever (test (key el)) returns true.

Furthermore,

[10]> (remove-if-not #'(lambda(x)(= 2 x)) '( (1) (2 2) (3 3 3)) :key #'length)
((2 2))
[11]> (remove-if-not #'(lambda(x)(/= 2 x)) '( (1) (2 2) (3 3 3)) :key #'length)
((1) (3 3 3))
[12]> (defvar qq '( (1) (2 2) (3 3 3)))
QQ
[13]> (remove-if-not #'(lambda(x)(/= 2 x)) qq :key #'length)
((1) (3 3 3))
[14]> qq
((1) (2 2) (3 3 3))
[15]> (eq qq (remove-if-not #'(lambda(x)(/= 2 x)) qq :key #'length))
NIL
[16]> (eq qq (remove-if-not #'(lambda(x)(/= 22 x)) qq :key #'length))
T
[17]>

So we don't really need to see the actual source code to find out what it does.

So the test lambda function gets called for each element in the sequence, for instance

(funcall #'(lambda(x)(/= 2 x)) (length '(1)))
=
((lambda (x) (/= 2 x)) (length '(1)))
=
(let    ((x            (length '(1))))
             (/= 2 x))
=
T

That's how function calls are made -- the lambda function's parameter gets the value of the argument in the function call, and then the lambda function's body gets evaluated under this binding.

Will Ness
  • 70,110
  • 9
  • 98
  • 181
1

It's filled in my remove-if-not. It contains a loop that calls your function, passing the current element of the list as the argument.

Ignoring all the options that remove-if-not takes, it's essentially:

(defun remove-if-not (func list)
  (loop for item in list
        if (not (funcall func item))
        collect item))

Your lambda gets the argument from (funcall func item)

Barmar
  • 741,623
  • 53
  • 500
  • 612
  • wow... i didnt get that from the clhs when i read it. I am curious, with elisp it's pretty easy to read the function I want to learn about. How can I go deeper that (documentation...) and read the whole function/macro for CL functions? – Vinn Nov 11 '22 at 19:00
  • There are open-source Common Lisp implementations. See https://common-lisp.net/implementations for a list. – Barmar Nov 11 '22 at 19:40
  • I understand. Using SBCL as an example, where can I read the `remove-if-not` function source code? I cannot find it on github either. – Vinn Nov 12 '22 at 02:11
  • Usually i install sbcl from source, compile it with "./make.sh --fancy", and when doing so I'm sure all the source code is accessible by pressing meta-dot (M-.) in emacs/swank – coredump Nov 12 '22 at 23:27
  • https://github.com/sbcl/sbcl/blob/d35ad6f9bee212499cb827fec3195bf2064c10a2/src/pcl/sequence.lisp#L1035 – Barmar Nov 14 '22 at 07:20