Vinn
Vinn

Reputation: 1181

How does this lambda get its function argument in common lisp?

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?

Upvotes: 2

Views: 106

Answers (2)

Will Ness
Will Ness

Reputation: 71065

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.

Upvotes: 2

Barmar
Barmar

Reputation: 780974

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)

Upvotes: 1

Related Questions