This is a read-only archive of lispforum.com. The forum was locked to new users and posts and is preserved here as static HTML from a database snapshot taken on 2019-09-07.

Defining a lexically scoped function.

13 posts · 2244 views

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:
(setf (fdefinition `foo) #'bar)
This could probably work, maybe with some inspection to accept the correct arguments, but doesn't really solve anything:
(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

Re: Defining a lexically scoped function.

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:
(flet ((lexical-alias (&rest args)
         (apply variable-holding-your-function args)))
  ...)
But that is neither a macro nor obscure.

Re: Defining a lexically scoped function.

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:
function foo(){
    function bar(){
        return function (){
            alert(70 * 7);
        }
    }
    baz = bar();
}
This makes `baz' local to `foo', which is what I want:
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).
function foo(){
    function bar(){
        return function (){
            alert(70 * 7);
        }
    }
    function baz(){
        return bar();
    }
}
I'm off my grokker.
- Chris

Re: Defining a lexically scoped function.

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.

Re: Defining a lexically scoped function.

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

Re: Defining a lexically scoped function.

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.
(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)))

Re: Defining a lexically scoped function.

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

Re: Defining a lexically scoped function.

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.

Re: Defining a lexically scoped function.

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

Re: Defining a lexically scoped function.

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.

Re: Defining a lexically scoped function.

Oh, OK. I think I need to start a list of macros to be written... Thanks again. :)
I'm off my grokker.
- Chris

Re: Defining a lexically scoped function.

It might be best to back up a bit: this whole discussion has been about implementation details.

What is it that you're trying to do? It may be that you're unwittingly trying to write Javascript in Lisp; while that can be done if you really must, the languages are pretty wildly different - the JS approach may involve a workaround to a limitation that CL doesn't have. It could well be that you're better off with a different solution altogether in CL. Could you describe the actual problem at hand? We can look over that, and suggest good approaches that leverage this language's strengths.

Re: Defining a lexically scoped function.

Lol, how'd you guess? I'm wittingly implementing the JS object-model in CL, as an exercise. And I'm almost done; I only need to implement inheritance and, non-essentially, functions. After that I might start simplifying it by removing all JS functions including constructors, and maybe even look into avoiding destructive operations (probably impossible).
I'm off my grokker.
- Chris