Page 1 of 1

Passing arguments to find-if

Posted: Sun Jan 18, 2015 4:04 pm
by j831526
I don't understand the following compile error using CCL on Mac OSX:

Code: Select all

(setf tbl '((foo fee) (flubber mcgee)))
(defun look-up (key field-func table)
     (find-if #'(lambda (x)
                   (equal (field-func x) key))
             table))
(look-up 'flubber #'first tbl)
I get the following error:

? (load "~/Code/Lisp/my-lib.lisp")
;Compiler warnings for "/Users/charlesparker/Code/Lisp/my-lib.lisp" :
; In LOOK-UP: Unused lexical variable FIELD-FUNC
> Error: Undefined function FIELD-FUNC called with arguments ((FOO FEE)) .
> While executing: (:INTERNAL LOOK-UP), in process Listener(4).
> Type cmd-/ to continue, cmd-. to abort, cmd-\ for a list of available restarts.
> If continued: Retry applying FIELD-FUNC to ((FOO FEE)).
> Type :? for other options.
1 > q

Since field-func should be a local variable in look-up, shouldn't it be available to the lambda function?

Thanx for any help - Charlie

Re: Passing arguments to find-if

Posted: Sun Jan 18, 2015 4:43 pm
by Kohath
It's probably a confusion around Lisp-1 vs Lisp-2 (http://en.wikipedia.org/wiki/Common_Lis ... _namespace). You are writing in Lisp-1 style, like Scheme. To fix it, call the passed function with funcall:

Code: Select all

(defun look-up (key field-func table)
    (find-if #'(lambda (x)
                  (equal (funcall field-func x) key))
            table))

Re: Passing arguments to find-if

Posted: Sun Jan 18, 2015 10:32 pm
by j831526
Kohath,

Thanx - that was it.

lisp1 vs. lisp2??? I'm definitely missing something! I'm learning Lisp from Touretzky's book, "Common Lisp" which was re-published by Dover in 2013. It was originally published in 1990 which I guess is where the lisp1 comes in.

I chose Common Lisp over Scheme simply because the Apple App store made it free and easy to install Clozure Common Lisp. Not sure I made the best choice:(

Charlie

Re: Passing arguments to find-if

Posted: Mon Jan 19, 2015 12:33 am
by edgar-rft
j831526 wrote: lisp1 vs. lisp2???
  • lisp-1 (e.g. Scheme) means that a symbol can be only one of both: a function or a variable
  • lisp-2 (e.g. Common Lisp) means that a symbol can be both at the same time: a function and a variable
Don't worry too much about this yet. David Touretzky explains in later chapters of the book why a in Common Lisp a symbol can be both, a function as well as a variable, and how to deal with special cases.
j831526 wrote: Since field-func should be a local variable in look-up, shouldn't it be available to the lambda function?
In your code the symbol find-func is used by the look-up function as a parameter variable, and in the body of look-up you want the value of the find-func variable to be called as a function. In Common Lisp, to call the variable value of a symbol as a function you need FUNCALL or APPLY.

The "undefined function FIELD-FUNC" error happens because Common Lisp doesn't understand that it's the variable value of find-func that you want to be called, so instead it looks for a function named find-func that it can't find because there was no find-func function defined with DEFUN before.

As a rule of thumb:
  • In a lisp-2 (Common Lisp) function call, if a symbol is the first element of a list, the SYMBOL-FUNCTION value of the unevaluated symbol is used, and if a symbol is at any other position in the list, the SYMBOL-VALUE (the variable value) of the evaluated symbol is used.
  • In a lisp-1 (Scheme) procedure call always the value of the evaluated symbol is used, independent of the symbol's position in the list. This is possible because Scheme symbols cannot have different values at the same time.
That a Common Lisp symbol can have different values is a common source of confusion for people who first have learned Scheme, and later start learning Common Lisp.

In Common Lisp this means that:
  • (field-func x) - here field-func is the first element in the list, so Common Lisp looks for a function named field-func
  • (funcall field-func x) - here field-func is not the first element in the list, so FUNCALL calls the variable value of field-func as a function with the argument x
In Common Lisp the special evaluation rule for the first element is necessary because otherwise it wouldn't be possible to tell if the symbol is a function or a variable.
j831526 wrote: Apple App store ... Clozure Common Lisp ... Not sure I made the best choice.
I have no particular experience with the Apple App store version, but I can tell that Clozure Common Lisp (CCL) in general is known to be a good and stable Common Lisp implementation.

- edgar

Re: Passing arguments to find-if

Posted: Mon Jan 19, 2015 10:47 am
by j831526
Edgar,

Thanx for the EXCELLENT detailed explanation!

Charlie