Dynamically defined functions?

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

Dynamically defined functions?

Post by Jesdisciple » Sun Feb 14, 2010 8:11 pm

I want to define a function's lambda-list at runtime. As I read the HyperSpec this should be possible, specifically because an identifier can be either a symbol or a string. But this code:

Code: Select all

(defvar foo (list "bar" "baz"))
(defun test foo (print "qux"))
gives this error:

Code: Select all

DEFUN: Lambda lists with dots are only allowed in macros, not here: FOO
   [Condition of type SYSTEM::SIMPLE-PROGRAM-ERROR]
I got the "lambda lists with dots" error before but somehow got around it without understanding it. What in the world is a lambda list with a dot?

Once I get this working I'm also going to look into doing the same for the function's body, which I think fits within this thread.

Thanks.
I'm off my grokker.
- Chris

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

Re: Dynamically defined functions?

Post by nuntius » Sun Feb 14, 2010 8:21 pm

The code you've shown would probably work better as a macro. If you really want to define functions at runtime, I'd recommend something more like

Code: Select all

(setf (symbol-function 'test)
      (lambda (bar baz)
        (print 'quux)))

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

Re: Dynamically defined functions?

Post by Jesdisciple » Sun Feb 14, 2010 8:31 pm

Erm... I'm not sure I was clear. The lambda-list will be passed into the containing function (along with the body), which is why I bound it to its own symbol; I think LAMBDA is irrelevant to that problem.

I didn't think a macro would help because I need the operator to know the containing function's arguments. A macro would be expanded before the function is ever called and not offer any benefits functionality-wise. I actually thought a special operator that reverses the effect of QUOTE would be necessary.
http://www.lispworks.com/documentation/HyperSpec/Body/s_quote.htm wrote:Some objects, called self-evaluating objects, do not require quotation by quote. However, symbols and lists are used to represent parts of programs, and so would not be useable as constant data in a program without quote. Since quote suppresses the evaluation of these objects, they become data rather than program.
I'm off my grokker.
- Chris

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

Re: Dynamically defined functions?

Post by ramarren » Sun Feb 14, 2010 11:54 pm

Jesdisciple wrote:As I read the HyperSpec this should be possible, specifically because an identifier can be either a symbol or a string.
Where does it say that? And anyway, that is irrelevant to what you are trying to do, unless I mistaken in what that is.

Remember, Common Lisp is supposed to be easily compiled. Knowing function signatures at compile time is rather important to that goal. What you can do is define a function with a single &rest argument, and then destructure it in any way you want:

Code: Select all

(defvar *foo* (list "bar" "baz"))

(defun test (&rest foo)
  (let ((dynamic-args (pairlis *foo* foo)))
    (print (cdr (assoc "bar" dynamic-args :test #'string=)))
    (print (cdr (assoc "baz" dynamic-args :test #'string=)))
    (values)))

;; CL-USER> (test "abc" "def")

;; "abc" 
;; "def" 
;; ; No value
This is quite verbose, but some of it can be automated with proper functions/macros, and some is just necessary because you are fighting with the language. What is the point, anyway? When writing code you already have to know what arguments function takes in order to use them. If done programmaticaly then just pass a single argument with compound datastructure and either use generic function or typecase.

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

Re: Dynamically defined functions?

Post by Jesdisciple » Mon Feb 15, 2010 12:15 am

I followed the links from lambda list > parameter > variable > binding > name > identifier. I thought it was relevant because instead of literal symbols I was passing strings, which seems to be explicitly allowed.

But yes, I did anticipate that it would be a compiler optimization. I just hoped there would be a way, because the program would be a bit smoother (and I love using language features that let you just type what you mean even if it doesn't look like it should work).

I have a &rest function that operates as a middle-man to the user-generated function. The middle-man prefixes the argument list with the value of `this' and passes it on to the user's function. I was hoping to not have to declare functions with a reserved first parameter like in Python, but oh well. I'll just have the user pass a lambda that takes "this" as that first parameter.

I'm trying to design this in such a way that a JavaScript parser could be plugged (almost) directly into it. But even short of that, I both want to do it and want to see how prototypes (another of those language features I love) mix with Lisp. The code I'm writing right now, though, won't stay in anything I actually use in Lisp - even as a toy. It's just a compatibility layer for the parser, which I want to write once I'm advanced enough.

EDIT: Oh, but what is a lambda list with dots?
I'm off my grokker.
- Chris

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

Re: Dynamically defined functions?

Post by ramarren » Mon Feb 15, 2010 1:00 am

Jesdisciple wrote:I followed the links from lambda list > parameter > variable > binding > name > identifier. I thought it was relevant because instead of literal symbols I was passing strings, which seems to be explicitly allowed.
This might be true for lambda lists in some very general way, but DEFUN is specified to take an ordinary lambda list which is further specified to require symbols.
Jesdisciple wrote:I have a &rest function that operates as a middle-man to the user-generated function. The middle-man prefixes the argument list with the value of `this' and passes it on to the user's function. I was hoping to not have to declare functions with a reserved first argument like in Python, but oh well. I'll just have the user pass a lambda that takes "this" as that first argument.
An alternative would be to use a special variable. That is not exactly idiomatic, but by this point there is no reason to worry about that. Remember that special variables are not simply global variables, they can be bound and rebound within some dynamic contour. Instead of prefixing the argument list you would just bind the special.
Jesdisciple wrote:and want to see how prototypes (another of those language features I love) mix with Lisp
There are already several libraries implementing prototypes in Common Lisp. The most active right now is Sheeple. It seems to mix rather well.
Jesdisciple wrote:EDIT: Oh, but what is a lambda list with dots?
Those are lambda lists used by DEFMACRO and DESTRUCTURING-BIND, and they allow destructuring, which is sort of limited pattern matching.

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

Re: Dynamically defined functions?

Post by Jesdisciple » Mon Feb 15, 2010 9:09 pm

Ramarren wrote:This might be true for lambda lists in some very general way, but DEFUN is specified to take an ordinary lambda list which is further specified to require symbols.
Oops, I thought I read through that page.
Ramarren wrote:An alternative would be to use a special variable. That is not exactly idiomatic, but by this point there is no reason to worry about that. Remember that special variables are not simply global variables, they can be bound and rebound within some dynamic contour. Instead of prefixing the argument list you would just bind the special.
Sweet - and it's prettier too! I just read through that part of the tutorial; why didn't I think of that?
Ramarren wrote:There are already several libraries implementing prototypes in Common Lisp. The most active right now is Sheeple. It seems to mix rather well.
Gah, every time I think of something cool someone's already beat me to it. Oh well, I'm still learning a lot about CL - what it can, can't, and shouldn't do. ;)
Ramarren wrote:Those are lambda lists used by DEFMACRO and DESTRUCTURING-BIND, and they allow destructuring, which is sort of limited pattern matching.
Ahh... BTW, is there anywhere that explains CLisp's error messages? All Google can find is a list of all possible ones, duplicated across many sites and lacking any explanation.

Thanks!
I'm off my grokker.
- Chris

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

Re: Dynamically defined functions?

Post by ramarren » Tue Feb 16, 2010 12:05 am

Jesdisciple wrote:BTW, is there anywhere that explains CLisp's error messages? All Google can find is a list of all possible ones, duplicated across many sites and lacking any explanation.
I don't think so, at least I have never seen such a thing. After some time you just get enough experience that they become mostly self-explanatory. Looking at the backtrace is usually helpful as well.

Post Reply