Local functions in common Lisp?

Discussion of Common Lisp
Post Reply
j831526
Posts: 11
Joined: Mon Nov 10, 2014 4:24 pm

Local functions in common Lisp?

Post by j831526 » Mon Dec 22, 2014 7:22 pm

I want to hide as a local a helper function within its parent function.

Code: Select all

(defun fubar (x)
   (defun feebar (y)
      ...)
   ...)
doesn't work because feebar becomes a global (at least it's global in the REPL which is my sandbox).

Next I tried this:

Code: Select all

;; my-reverse
(defun my-reverse (ol)
    (let (foo #'(lambda (x y)
                (if (equal x nil)
                    y
                    (foo (rest x) (cons (first x) y)))))
        (foo ol nil)))
which generates these compiler warnings I don't understand:

;Compiler warnings for "/Users/charlesparker/Code/Lisp/TryIt.lisp" :
; In MY-REVERSE: Unused lexical variable FUNCTION
;Compiler warnings for "/Users/charlesparker/Code/Lisp/TryIt.lisp" :
; In MY-REVERSE: Unused lexical variable FOO

but my-reverse seems to work:
? (my-reverse '(1 2 3))
(3 2 1)

however, so does this:
(foo '(1 2 3) nil)
(3 2 1)

I assumed locally defined functions would have similar scoping rules as locally defined variables. What's the deal?

Thanx - Charlie

nuntius
Posts: 538
Joined: Sat Aug 09, 2008 10:44 am
Location: Newton, MA

Re: Local functions in common Lisp?

Post by nuntius » Mon Dec 22, 2014 8:19 pm

So DEFUN defines a global function, even when nested in another function.
So its actually easy (and sometimes encouraged) to write functions that create other functions...

I'm not sure why FOO is working, but there's a good chance some DEFUN in the past brought it into existence.

Use FLET or LABELS to define local functions.

http://www.lispworks.com/documentation/ ... _flet_.htm

Also, your LET call appears to be missing a set of parens. Normal usage is (let ((x1 v1) (x2 v2)) (body)).
The statement (let (x1 v1) (body)) actually treats x1 and v1 as variables bound to NIL...

j831526
Posts: 11
Joined: Mon Nov 10, 2014 4:24 pm

Re: Local functions in common Lisp?

Post by j831526 » Tue Dec 23, 2014 12:22 am

Nuntilus,

Thanx for the suggie and the doc pointer. This version works, and the inner function, fee, is invisible from the top REPL level.

Code: Select all

(defun my-reverse2 (ol)
    (labels ((fee (x y)
               (if (equal x nil)
                   y
                   (fee (rest x) (cons (first x) y)))))
        (fee ol nil)))
A couple of observations:
1) I was missing a set of parens in the LET form of my-reverse1. Nothing changed when I added them! This is probably because I only had a single binding which must have been ok without the extra list level because both versions worked. This was NOT due to any prior definitions lying around. I closed my listener (REPL) window, opened a new one, loaded the code, and ran. Same results with and without the additional parens. Presumably, this would not be true if I'd tried to initialize a second variable:)

2) FLET wouldn't compile because of the recursive call. Your doc pointer explained why:) LABELS worked without exposing the inner function (fee) to the REPL.

Thanx - Charlie

Post Reply