home *** CD-ROM | disk | FTP | other *** search
- Path: sparky!uunet!newsflash.concordia.ca!mizar.cc.umanitoba.ca!access.usask.ca!cs.Usask.CA!coulman
- From: coulman@cs.Usask.CA (Randy Coulman)
- Newsgroups: comp.lang.lisp
- Subject: SUMMARY: Functions
- Date: 18 Dec 1992 18:50:33 GMT
- Organization: University of Saskatchewan
- Lines: 206
- Sender: coulman@skorpio (Randy Coulman)
- Distribution: world
- Message-ID: <1gt6hpINNn01@access.usask.ca>
- Reply-To: coulman@cs.Usask.CA
- NNTP-Posting-Host: skorpio.usask.ca
-
- I recently posted a message here asking some questions about lambda
- expressions. I promised a summary, so here it is (along with my
- original post). Thank you to all who responded.
-
- --- Original message:
- I'm currently building an application using Allegro CL 4.1 and CLIM 1.1 on
- a Sparc 1+. One piece of functionality I need to include in my application
- is to allow users to specify and edit functions. These functions would
- ideally be lambda expressions. Later, the application would use apply or
- funcall to use the lambda expressions. Unfortunately, the new standard says
- that lambda expressions are no longer valid function arguments to funcall
- and apply. Instead, it is necessary to use #'(lambda ... instead of
- '(lambda ... I can easily make it a requirement that these functions need
- to be specified with #'. However, this takes away the ability to later edit
- the function.
-
- As an example, my application uses a class of object called Observers. Each
- observer knows how to make one binary (i.e., t or nil) observation about the
- real world. This is accomplished through the use of an observer function
- (ofun). The application I'm building allows the user to define new
- observers, so they need to be able to define the ofun's as well. E.g.:
-
- Defining Observer...
- Name: Always
- Ofun: '(lambda (c)
- (declare (ignore c))
- t)
- ...
-
- If I use #'(lambda ... above, then editing would look like this:
-
- Editing Observer...
- Name: Always
- Ofun: #<Interpreted Function (unnamed) @ ...>
-
- Am I missing something completely obvious about how to get around this
- problem? If not, can anyone suggest a reasonable work around?
-
- The way I'm doing it now is to define these functions in a source file,
- giving them names (strings) and storing them in a hash table. If the user
- wants to define new functions, they have to edit the source file before
- loading the system. This is not acceptable.
-
- Thanks in advance for any help.
-
- --- Timothy B. Moore replied:
- Use eval. That's what funcall and apply did when you could pass lambda
- expressions to them.
- ---
- That's an obvious solution. I don't know if I thought of it, but I have an
- incredible aversion to eval, so I may have just dismissed the idea as soon
- as I thought of it.
-
- --- Eyvind Ness replied:
- I think this is mentioned in the FAQ, but anyway:
-
- If you have a lambda list, like '(lambda (c) (declare (ignore c)) t),
- and want to funcall or apply it, simply use:
-
- (apply/funcall (coerce '(lambda (c) (declare (ignore c)) t) 'function) ...)
-
- In CMU CL (the only Lisp I have that is strictly CLtL2 compliant), I
- get:
-
- magica(bash)$ lisp
- ;; Loading "/nfs/lilleulv/users/eyvind/init.lisp".
- ;;; Sun 13-Dec-92 2:36:26 PM
- CMU Common Lisp 16e, running on magica
- Send bug reports and questions to your local CMU CL maintainer, or to
- cmucl-bugs@cs.cmu.edu.
- Loaded subsystems:
- Python 1.0, target SPARCstation/Sun 4
- CLOS based on PCL version: March 92 PCL (2a)
- * (funcall '(lambda (c) (declare (ignore c)) t) nil)
-
- Type-error in "DEFUN FUNCALL":
- (LAMBDA (C) (DECLARE (IGNORE C)) T) is not of type (OR FUNCTION SYMBOL)
-
- Restarts:
- 0: [ABORT] Return to Top-Level.
-
- Debug (type H for help)
-
- ("DEFUN FUNCALL" (LAMBDA (C) (DECLARE #) T) 3670168 1)[:OPTIONAL]
- 0] q
-
- * (funcall (coerce '(lambda (c) (declare (ignore c)) t) 'function) nil)
-
- T
- *
-
- as expected.
- ---
-
- I like this idea. It is probably the way I'll go. I never even thought of
- coerce, but it makes sense.
-
- --- Barry Margolin replied:
- In dpANS CL, you can convert a lambda expression to a function with (COERCE
- <lambda-exp> 'FUNCTION). You can also use (COMPILE NIL <lambda-exp>).
-
- In CLtL1 CL you can get the equivalent of the COERCE with
-
- (eval `#',<lambda-exp>)
-
- In order for you to allow users to edit the functions later, you can
- remember the original lambda expressions in a table keyed off the function.
- ---
-
- As above, I like this idea best.
-
- --- donc@ISI.EDU replied:
- The problem here is that you seem to think that the function to be applied
- must be the SAME as its specification. Why not read in the specifications
- as lambda expressions, but then process them a little more (in addition to
- what read does) to get functions? You certainly have to keep the source
- form (the lambda expression read as a list, or the characters from which
- read produced the list) in order to allow the user to edit it. However,
- after you read it you can make a functional version for use by apply.
- There are two ways to do this. One is compile. The other is coerce (to
- type function).
- ---
-
- I did realize that I would have to do something with the lambda expression
- that I read in. The problem was that I didn't know what that something
- would be. Again, I'll likely use the coerce solution.
-
- --- John (postmaster@aspen.CS.Berkeley.EDU replied:
- Don't use funcall, use eval instead!
- I assume you aren't trying to export local variables and so just
- say: (eval `(,result ,argument)) where "argument" is the value
- you want passed in as "c", and "result" is the list "(lambda (c) ..."
- returned after the editing session.
-
- John
- ---
-
- As above, I have this aversion to eval. But this option would do the trick
- as well.
-
- --- Bruce Krulwich replied:
- Your approach strikes me as dangerous. What about name overlaps? What about
- the user doing something that would kill the system?
-
- If it were me, I would probably write my own small interpreter for the
- functions the user is writing. Actually, there are plenty of small rule
- interpreters around -- all you'd have to add were whatever looping constructs
- or other high-level constructs you wanted.
-
- Once you have a small vocabulary for rules the user is defining, you could in
- fact make a small compiler for them, that decomposes the rules the user enters
- and constructs actual closures using LAMBDAs. The value of doing this depends
- on how critical speed is and how rich your rule vocabulary is.
-
- I hope this was clear and helps.
- ---
-
- This was a very interesting reply. I hadn't thought a lot about these kind
- of issues. This is a research system that would only be used by knowledge
- engineers, so I think I can assume that there won't be any malicious
- intent. If we decide to distribute this system a little more widely, then
- I'll have to reconsider these issues.
-
- There are some problems here, though. In general, any operations that will
- be performed in these functions will be (no-side-effect) operations on the
- argument to the function. However, in some cases, there are side effects
- that would be desired. For example, one system we are building with this
- environment uses these observers to recognize primitive Lisp things. There
- would have to be observers that can recognize the name of a defined
- function and its arguments. However, there also needs to be observers that
- can recognize a recursive call to this function and other calls using the
- function's arguments. In this case, the observers which originally
- recognize the function name and argument list must somehow store this
- information for the other observers to access.
-
- This application is a knowledge-engineering toolkit, and we intend it to be
- extensible/customizable for different application domains. Thus, we don't
- want to put any a priori constraints on what these observers can and cannot
- do. For example, in the Lisp domain again, the observer may want to
- recognize recursion by tracing the execution of the function to see if it
- calls itself somewhere.
-
- This response did make me think about these sort of issues, however, and I
- appreciate that.
-
- --- Richard Lynch replied:
-
- I think if you keep the lambda list for editing, and call it with:
-
- (funcall (function <lambda-list>) <args?>)
- ^^^^^^^^
- this should work.
- ---
-
- I thought of this as well, but function doesn't evaluate its argument.
-
- Thanks again for all of the replies. I haven't had a chance to implement
- the suggestions contained here, but will do so in the near future.
-
- Randy
-
- --
- Randy A. Coulman | ARIES Laboratory
- Research Assistant | Department of Computational Science
- | University of Saskatchewan
- coulman@cs.Usask.ca | Saskatoon, SK S7N 0W0
-