Defining a lexically scoped function.

Discussion of Common Lisp
Jesdisciple
Posts: 26
Joined: Thu Feb 04, 2010 5:56 pm

Defining a lexically scoped function.

Post by Jesdisciple » Mon Feb 08, 2010 11:44 pm

I want to alias a function as another lexically scoped function. The function to be aliased is returned by another function, which is the reason I want to alias it - so it can be cached. I think this was working but I abandoned it when I read somewhere that fdefinition returns a global:

Code: Select all

(setf (fdefinition `foo) #'bar)
This could probably work, maybe with some inspection to accept the correct arguments, but doesn't really solve anything:

Code: Select all

(labels (foo (&rest args) (bar @,args)))
Grr...

Is there some obscure macro that does what I'm wanting, or maybe I can use whatever such a macro would use?
I'm off my grokker.
- Chris

ramarren
Posts: 613
Joined: Sun Jun 29, 2008 4:02 am
Location: Warsaw, Poland
Contact:

Re: Defining a lexically scoped function.

Post by ramarren » Tue Feb 09, 2010 1:53 am

Jesdisciple wrote:Is there some obscure macro that does what I'm wanting, or maybe I can use whatever such a macro would use?
I don't really understand what you want... if you want to establish a lexical function calling a function stored in variable, the you can just do:

Code: Select all

(flet ((lexical-alias (&rest args)
         (apply variable-holding-your-function args)))
  ...)
But that is neither a macro nor obscure.

Jesdisciple
Posts: 26
Joined: Thu Feb 04, 2010 5:56 pm

Re: Defining a lexically scoped function.

Post by Jesdisciple » Tue Feb 09, 2010 6:42 pm

JavaScript was my first language and it's the best way I know to demonstrate what I mean. This makes `baz' a global variable, which is what `setf' allows me to do in CL:

Code: Select all

function foo(){
    function bar(){
        return function (){
            alert(70 * 7);
        }
    }
    baz = bar();
}
This makes `baz' local to `foo', which is what I want:

Code: Select all

function foo(){
    function bar(){
        return function (){ // anonymous function
            alert(70 * 7);
        };
    }
    var baz = bar();
}
And here is what `labels'/`flet' allows me to do. I don't like it because I still have to call a function (an extra function - wrong direction!) every time I want that other function (the anonymous one).

Code: Select all

function foo(){
    function bar(){
        return function (){
            alert(70 * 7);
        }
    }
    function baz(){
        return bar();
    }
}
I'm off my grokker.
- Chris

ramarren
Posts: 613
Joined: Sun Jun 29, 2008 4:02 am
Location: Warsaw, Poland
Contact:

Re: Defining a lexically scoped function.

Post by ramarren » Wed Feb 10, 2010 12:02 am

Jesdisciple wrote:This makes `baz' a global variable, which is what `setf' allows me to do in CL:
SETF doesn't create variables, global or otherwhise. SETF sets places. Using SETF on an undefined place, in particular nonexistent variable, is undefined. Most implementations will create a special-dynamic variable, but many will signal a warning. The reason for that is that it allows catching typos in variable names. Creating global variables is done with DEFPARAMETER/DEFVAR and shouldn't really be done at runtime anyway.
Jesdisciple wrote:JavaScript was my first language and it's the best way I know to demonstrate what I mean.
Javascript is essentially a mutated version of Scheme. Scheme is Lisp-1, and Common Lisp is not. You either have to assign functions to variables bound by LET, and call them with FUNCALL/APPLY, or establish a local wrapping function with FLET/LABELS.

I don't really see why the latter would be insufficient. I suppose it would be a little more verbose, but that is just a macro away. There is no performance hit from the additional function call if the wrapping function is declared INLINE.

Jesdisciple
Posts: 26
Joined: Thu Feb 04, 2010 5:56 pm

Re: Defining a lexically scoped function.

Post by Jesdisciple » Wed Feb 10, 2010 1:55 pm

Ramarren wrote:SETF doesn't create variables, global or otherwhise. SETF sets places. Using SETF on an undefined place, in particular nonexistent variable, is undefined.
I get the difference between places, variables and functions, but I was using JS terminology at the time, where they all get muddled together. But anyway, this is where I got the idea that (setf fdefinition) makes a new function symbol:
http://www.ai.mit.edu/projects/iiip/doc/CommonLISP/HyperSpec/Body/acc_fdefinition.html wrote:An error of type undefined-function is signaled in the non-setf case if function-name is not fbound.
I guess I read too much into that?
Ramarren wrote:Javascript is essentially a mutated version of Scheme. Scheme is Lisp-1, and Common Lisp is not. You either have to assign functions to variables bound by LET, and call them with FUNCALL/APPLY, or establish a local wrapping function with FLET/LABELS.

I don't really see why the latter would be insufficient. I suppose it would be a little more verbose, but that is just a macro away. There is no performance hit from the additional function call if the wrapping function is declared INLINE.
`bar' is a function factory which returns essentially the same function every time, but the returned function has a state in its closure which is to be modified by user code. Unless I can cache this returned function, my objective is impossible.

But you mentioned that `let' can also define a function symbol...?
I'm off my grokker.
- Chris

ramarren
Posts: 613
Joined: Sun Jun 29, 2008 4:02 am
Location: Warsaw, Poland
Contact:

Re: Defining a lexically scoped function.

Post by ramarren » Wed Feb 10, 2010 2:22 pm

Jesdisciple wrote:new function symbol
There are no function symbols. A symbol is conceptually a structure with a number of fields. It is usually no implemented like that because for a majority of symbols some of those fields will be empty, so it would be a waste of space. But however they are implemented the specification defines five accessors, one of which is SYMBOL-FUNCTION, which holds a function. A symbol with a function in this field names the function, but there is nothing special about it. FDEFINITION is different from SYMBOL-FUNCTION in that it take a function name, which can be more than a symbol, but when given a symbol it is more or less equivalent.

What I am trying to say is that function are first class values independent of symbols. You can bind them to variables, put then in list, arrays, hashtables, objects or whatever directly. The wrapper function would only be there in order to avoid using FUNCALL/APPLY when calling it, but there is not much point.

Code: Select all

(defun make-accumulator ()
  (let ((total 0))
    (lambda (x)
      (incf total x))))

(let ((variable1 (make-accumulator))
      (variable2 (make-accumulator)))
  (print (funcall variable1 3))
  (print (funcall variable2 2))
  (print (funcall variable1 4))
  (print (funcall variable2 8)))

Jesdisciple
Posts: 26
Joined: Thu Feb 04, 2010 5:56 pm

Re: Defining a lexically scoped function.

Post by Jesdisciple » Wed Feb 10, 2010 4:19 pm

I guess I was thinking of "field" rather than "symbol" then. I've seen many new terms this past week. :) But I was actually thinking the symbol was an index in one of several hash tables (scopes) - function scope being one. Or am I misusing "scope" as well?

But yes, LET is what I was looking for, so thanks! I can't believe I didn't see (or notice, rather) anything about that, as much as I looked.

EDIT: The workaround I developed for the global scope is:

Code: Select all

(defun foo () )
(setf (fdefinition `foo) ((lambda ()
                           #| ... |#)))
(foo)
Would this work with LABELS/FLET as well?
I'm off my grokker.
- Chris

ramarren
Posts: 613
Joined: Sun Jun 29, 2008 4:02 am
Location: Warsaw, Poland
Contact:

Re: Defining a lexically scoped function.

Post by ramarren » Thu Feb 11, 2010 12:01 am

Jesdisciple wrote:I guess I was thinking of "field" rather than "symbol" then. I've seen many new terms this past week.
Well, "field" might not actually be a Common Lisp term, I just thought it would be clearer than "slot", which applies to objects anyway. I am not sure what name to whatever is that symbols contain is. They are accessible only by accessor functions, anyway.
Jesdisciple wrote:But I was actually thinking the symbol was an index in one of several hash tables
It might be implemented somewhat like that, but that is an implementation detail.
Jesdisciple wrote:(scopes) - function scope being one. Or am I misusing "scope" as well?
In this case I think you mean "function namespace". Scope is, more or less, the area of code where an identifier refers to a variable. You can read more about scope and extend in CLTL chapter 3.
Jesdisciple wrote:Would this work with LABELS/FLET as well?
Not directly. You cannot actually directly bind a lambda this way, you have to create a wrapping function, possibly inline, which will go through some variable, likely established by LET. This either a concession to implementing effective compilation or because CL was designed by committee, I don't know which.

Jesdisciple
Posts: 26
Joined: Thu Feb 04, 2010 5:56 pm

Re: Defining a lexically scoped function.

Post by Jesdisciple » Thu Feb 11, 2010 9:40 am

Ramarren wrote:In this case I think you mean "function namespace". Scope is, more or less, the area of code where an identifier refers to a variable. You can read more about scope and extend in CLTL chapter 3.
D'oh, I knew that.
Ramarren wrote:Not directly. You cannot actually directly bind a lambda this way, you have to create a wrapping function, possibly inline, which will go through some variable, likely established by LET.
Ew... But what do you mean by "a wrapping function ... [going] through some variable"?
I'm off my grokker.
- Chris

ramarren
Posts: 613
Joined: Sun Jun 29, 2008 4:02 am
Location: Warsaw, Poland
Contact:

Re: Defining a lexically scoped function.

Post by ramarren » Thu Feb 11, 2010 9:47 am

Jesdisciple wrote:Ew... But what do you mean by "a wrapping function ... [going] through some variable"?
I just mean what I did in the example in the first reply of this thread. Create a local function which only calls the function stored in a variable, then you can store the lambda in the variable but call the function without FUNCALL/APPLY.

Post Reply