Search code examples
lambdaargumentscommon-lispsbclfunction-call

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?


Solution

  • 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.