From: Oudeis
Subject: Funcalling from flet
Date: 
Message-ID: <9cca45d2.0308011615.64089836@posting.google.com>
Why doesn't this work (except when foo and bar are defined globally (with defun))?

(defun process-command-list (list)
    (flet 
        ((foo () 
             (print "foo"))
         (bar () 
             (print "bar"))) 
        (dolist (fun list) 
            (funcall fun)))) => process-command-list
(process-command-list '(foo bar bar)) => ...error...



Also, why does 

(defun dummy-function () 'top-level) =>  DUMMY-FUNCTION 
(flet ((dummy-function () 'shadow))
  (eq (funcall #'dummy-function)
      (funcall 'dummy-function))) => nil

work the way it works (example from the Hyperspec).

From: Matthew Danish
Subject: Re: Funcalling from flet
Date: 
Message-ID: <20030802011321.GE17568@lain.mapcar.org>
On Fri, Aug 01, 2003 at 05:15:19PM -0700, Oudeis wrote:
> Why doesn't this work (except when foo and bar are defined globally (with defun))?
> 
> (defun process-command-list (list)
>     (flet 
>         ((foo () 
>              (print "foo"))
>          (bar () 
>              (print "bar"))) 
>         (dolist (fun list) 
>             (funcall fun)))) => process-command-list
> (process-command-list '(foo bar bar)) => ...error...

Because FOO and BAR are *lexically defined functions* (by FLET) and are
only in scope within the body of FLET.  This means that they can only be
referred to from within the body of the FLET.  Also, lexically bound
functions are not associated with global symbols.

Much like A is only in scope in the body of LET in the following example:

(let ((a 1))
  a)

FOO is only in scope in the body of the FLET here:

(flet ((foo () t))
  (foo))

> Also, why does 
> 
> (defun dummy-function () 'top-level) =>  DUMMY-FUNCTION 
> (flet ((dummy-function () 'shadow))
>   (eq (funcall #'dummy-function)
>       (funcall 'dummy-function))) => nil
> 
> work the way it works (example from the Hyperspec).

#'dummy-function really means (FUNCTION DUMMY-FUNCTION).  FUNCTION is an
operator which looks up a function first in the local lexical
environment, and then in the global environment.  So, when you have
(funcall #'dummy-function) it is looked up in the local lexical
environment.  But (funcall 'dummy-function) is defined to look-up
dummy-function in the global environment, and that is a different
function as defined by DEFUN.  Functions defined by FLET are not
associated with symbols, remember.

-- 
; Matthew Danish <·······@andrew.cmu.edu>
; OpenPGP public key: C24B6010 on keyring.debian.org
; Signed or encrypted mail welcome.
; "There is no dark side of the moon really; matter of fact, it's all dark."
From: Pascal Costanza
Subject: Re: Funcalling from flet
Date: 
Message-ID: <costanza-625C97.03195502082003@news.netcologne.de>
In article <····························@posting.google.com>,
 ····@hotmail.com (Oudeis) wrote:

> Why doesn't this work (except when foo and bar are defined globally (with 
> defun))?
> 
> (defun process-command-list (list)
>     (flet 
>         ((foo () 
>              (print "foo"))
>          (bar () 
>              (print "bar"))) 
>         (dolist (fun list) 
>             (funcall fun)))) => process-command-list
> (process-command-list '(foo bar bar)) => ...error...

In the description of funcall you can find the following explanation:

"If function is a symbol, it is coerced to a function as if by finding 
its functional value in the global environment."

The important word here is "global". funcall doesn't see local function 
definitions.

> Also, why does 
> 
> (defun dummy-function () 'top-level) =>  DUMMY-FUNCTION 
> (flet ((dummy-function () 'shadow))
>   (eq (funcall #'dummy-function)
>       (funcall 'dummy-function))) => nil
> 
> work the way it works (example from the Hyperspec).

#' is an abbreviation for (function ...) and ' is an abbreviation for 
(quote ...). When you use ' to denote the function you actually give 
funcall just a symbol. As explained above, the function is then looked 
up in the global environment _at runtime_.

When you use #' to denote the function then the function is looked up 
_at compile-time_ [1]. In this case, it is possible to take local 
declarations into account, so the compiler picks the local function.

Why this distinction?

' is more dynamic in the sense that the global function binding might 
change - it is guaranteed that such changes are taken into account, so 
you will always get the most current function definition.

' does not take local function definitions into account because this 
would prohibit certain optimizations in the compilation stage. Therefore 
the alternative with #' is provided as well - this picks up the function 
at compile-time and does not take dynamic changes of a function into 
account.


I hope this helps.

Pascal


[1] Common Lisp doesn't require a compiler but in an interpreted setting 
it is required that the code behaves as if it was compiled in that 
regard. (A more precise description is given in the HyperSpec entry for 
the "function" special operator.)
From: Oudeis
Subject: Re: Funcalling from flet
Date: 
Message-ID: <9cca45d2.0308020518.1a81c1@posting.google.com>
Thank you all for excellent replies.

I understand that in order to call a local function, 
I need to give the funcall the value returned by the (function...) form.
But the problem is that I read the symbols naming the local functions from 
a list and (function...) does not evaluate its argument, so I can't do it 
like that:
(defun process-command-list (list)
    (let ((x 0)
          (y 0))
        (flet ((foo ()
                    (incf x))
               (bar ()
                    (decf x)
                    (incf y))
               (baz ()
                    (decf y)))
            (dolist (fun list)
                (funcall #'fun)))
        (values x y)))
(PROCESS-COMMAND-LIST '(foo foo bar baz foo))
From: Matthew Danish
Subject: Re: Funcalling from flet
Date: 
Message-ID: <20030802190638.GG17568@lain.mapcar.org>
On Sat, Aug 02, 2003 at 06:18:26AM -0700, Oudeis wrote:
> I understand that in order to call a local function, 
> I need to give the funcall the value returned by the (function...) form.
> But the problem is that I read the symbols naming the local functions from 
> a list and (function...) does not evaluate its argument, so I can't do it 
> like that:

Remember, FLET does lexical scope.  Lexical scope means that you can
/only/ refer to the function within the given boundaries.  If you could
somehow refer directly to those inner functions from the outside, then
it wouldn't be lexical scope =)  (that's not counting implementation
dependent hacks to pick out variables from closures; that's cheating)

Of course, nothing's stopping you from doing indirection.

-- 
; Matthew Danish <·······@andrew.cmu.edu>
; OpenPGP public key: C24B6010 on keyring.debian.org
; Signed or encrypted mail welcome.
; "There is no dark side of the moon really; matter of fact, it's all dark."
From: Pascal Costanza
Subject: Re: Funcalling from flet
Date: 
Message-ID: <costanza-26892C.15281102082003@news.netcologne.de>
In article <··························@posting.google.com>,
 ····@hotmail.com (Oudeis) wrote:

> Thank you all for excellent replies.
> 
> I understand that in order to call a local function, 
> I need to give the funcall the value returned by the (function...) form.
> But the problem is that I read the symbols naming the local functions from 
> a list and (function...) does not evaluate its argument, so I can't do it 
> like that:
> (defun process-command-list (list)
>     (let ((x 0)
>           (y 0))
>         (flet ((foo ()
>                     (incf x))
>                (bar ()
>                     (decf x)
>                     (incf y))
>                (baz ()
>                     (decf y)))
>             (dolist (fun list)
>                 (funcall #'fun)))
>         (values x y)))
> (PROCESS-COMMAND-LIST '(foo foo bar baz foo))

Two answers:

1) Why do you want to do that? It seems to me that your code becomes 
brittle because a client of process-command-list needs to have implicit 
knowledge about its internal implementation. Suppose that you want to 
change the implementation later (possibly years later) - do you still 
know all the call sites?

It might be a good idea to give more information about the "higher" 
problem that you actually want to solve. Maybe someone is able to come 
up with a better design alternative.


2) Of course, it is still possible to do what you want. Here is a sketch:

(defun process-command-list (list)
   (flet ((command-1 () (...))
          (command-2 () (...))
          ...)
     (dolist (fun list)
       (cond ((eq fun 'command-1) (command-1))
             ((eq fun 'command-2) (command-2))
             ((eq fun ...) ...)))))

...or instead of cond use one of case, ecase or ccase to save some 
typing and get better exception handling.


Pascal
From: Karsten Poeck
Subject: Re: Funcalling from flet
Date: 
Message-ID: <QbPWa.1655$w4.1130861@news-reader.eresmas.com>
the #'fun cannot  possibly work. what about
(defun process-command-list (list)
  (let ((x 0)
        (y 0))
    (labels ((foo ()
                  (incf x))
             (bar ()
                  (decf x)
                  (incf y))
             (baz ()
                  (decf y))
             (get-function (symbol)
                           (case symbol
                             (foo #'foo)
                             (bar #'bar)
                             (baz #'baz))))
      (dolist (fun list)
        (funcall (get-function fun))))
    (values x y)))

(PROCESS-COMMAND-LIST '(foo foo bar baz foo))

CL-USER(2):
2
0

Karsten
From: Coby Beck
Subject: Re: Funcalling from flet
Date: 
Message-ID: <bghgdd$2578$1@otis.netspace.net.au>
"Oudeis" <····@hotmail.com> wrote in message
·······························@posting.google.com...
> Thank you all for excellent replies.
>
> I understand that in order to call a local function,
> I need to give the funcall the value returned by the (function...) form.
> But the problem is that I read the symbols naming the local functions from
> a list and (function...) does not evaluate its argument, so I can't do it
> like that:
> (defun process-command-list (list)
>     (let ((x 0)
>           (y 0))
>         (flet ((foo ()
>                     (incf x))
>                (bar ()
>                     (decf x)
>                     (incf y))
>                (baz ()
>                     (decf y)))
>             (dolist (fun list)
>                 (funcall #'fun)))
>         (values x y)))
> (PROCESS-COMMAND-LIST '(foo foo bar baz foo))

I had a similar problem to solve a couple of years ago (at least my solution
seems it might work for you).  I had a server and received commands and
arguments via a socket connection.  The commands were symbol names but I did
not want to just blindly funcall whatever came in.  I defined a macro that
wrapped defmethod and did a bunch of stream work and constraint checking on
function parameters and also added the command name to a list.  Then the
function that executed the commands could verify that the command was
available before funcalling it.

So you could have:

(defmacro define-command (name args &body body)
  `(progn
     (defun ,name ,args
       ,@body)
     (pushnew ',name *commands*)))

(defun process-command-list (commands)
    (dolist (command commands)
        (when (member command *commands*)
            (funcall command))))

Now, you seem to need some shared local environment for your commands, that
is no problem:

(let ((x 0) (y 0))
    (define-command foo ()
      (incf x))
    (define-command bar ()
      (decf x)
      (incf y))
    (define-command baz ()
      (decf y))
    ;; some diagnostic utilities
    (defun check-state ()
        (values x y))
    (defun reset-state (&key (new-x 0) (new-y 0))
        (setf x new-x y new-y)))

Above, you return (values x y) from process-command-list.  That seems
curious, but assuming it was just to know what is going, I included the
check-state function above.

The above has some advantages over local functions: breaks up your code into
chewable chunks, makes it easier to add and extend commands, makes it easier
to test commands.

HTH.

-- 
Coby Beck
(remove #\Space "coby 101 @ big pond . com")