From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Pascal Bourguignon Newsgroups: gmane.emacs.help Subject: Re: Using setq to obtain a symbol from a list, so that I can assign a function to it Date: Tue, 22 Apr 2008 21:59:58 +0200 Organization: Informatimago Message-ID: <87zlrlvewx.fsf@hubble.informatimago.com> References: <48505b79-009c-42c9-912f-219a06474731@f24g2000prh.googlegroups.com> NNTP-Posting-Host: lo.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Trace: ger.gmane.org 1208897026 27949 80.91.229.12 (22 Apr 2008 20:43:46 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Tue, 22 Apr 2008 20:43:46 +0000 (UTC) To: help-gnu-emacs@gnu.org Original-X-From: help-gnu-emacs-bounces+geh-help-gnu-emacs=m.gmane.org@gnu.org Tue Apr 22 22:44:21 2008 connect(): Connection refused Return-path: Envelope-to: geh-help-gnu-emacs@m.gmane.org Original-Received: from lists.gnu.org ([199.232.76.165]) by lo.gmane.org with esmtp (Exim 4.50) id 1JoPLf-00049F-3j for geh-help-gnu-emacs@m.gmane.org; Tue, 22 Apr 2008 22:44:19 +0200 Original-Received: from localhost ([127.0.0.1] helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1JoPKz-0007uu-HV for geh-help-gnu-emacs@m.gmane.org; Tue, 22 Apr 2008 16:43:37 -0400 Original-Path: shelby.stanford.edu!newsfeed.stanford.edu!news.tele.dk!news.tele.dk!small.news.tele.dk!proxad.net!feeder1-2.proxad.net!cleanfeed3-a.proxad.net!nnrp14-2.free.fr!not-for-mail Original-Newsgroups: gnu.emacs.help Face: iVBORw0KGgoAAAANSUhEUgAAADAAAAAwAQMAAABtzGvEAAAABlBMVEUAAAD///+l2Z/dAAAA oElEQVR4nK3OsRHCMAwF0O8YQufUNIQRGIAja9CxSA55AxZgFO4coMgYrEDDQZWPIlNAjwq9 033pbOBPtbXuB6PKNBn5gZkhGa86Z4x2wE67O+06WxGD/HCOGR0deY3f9Ijwwt7rNGNf6Oac l/GuZTF1wFGKiYYHKSFAkjIo1b6sCYS1sVmFhhhahKQssRjRT90ITWUk6vvK3RsPGs+M1RuR mV+hO/VvFAAAAABJRU5ErkJggg== X-Accept-Language: fr, es, en X-Disabled: X-No-Archive: no User-Agent: Gnus/5.1008 (Gnus v5.10.8) Emacs/22.1 (gnu/linux) Cancel-Lock: sha1:Sz0poMGCkbj9IS3bVJqcG2vgoTs= Original-Lines: 226 Original-NNTP-Posting-Date: 22 Apr 2008 21:55:39 MEST Original-NNTP-Posting-Host: 88.180.86.168 Original-X-Trace: 1208894139 news-1.free.fr 23570 88.180.86.168:37757 Original-X-Complaints-To: abuse@proxad.net Original-Xref: shelby.stanford.edu gnu.emacs.help:158119 X-BeenThere: help-gnu-emacs@gnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Users list for the GNU Emacs text editor List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Original-Sender: help-gnu-emacs-bounces+geh-help-gnu-emacs=m.gmane.org@gnu.org Errors-To: help-gnu-emacs-bounces+geh-help-gnu-emacs=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.help:53481 Archived-At: srinik001@hotmail.com writes: > Hello, > > I would really appreciate some help on this. I am trying to do just > about everything with Emacs (and Emacs Lisp) these days. One of the > things I need to do in my job is to create XML files. I thought I > would use Emacs rather than some other editor/tool. > > So, I am trying to write a tool that will enable me to write specific > XML files by prompting me to enter values. Here is how I am trying to > do it. > > First, I set a variable that will provide a "grammar" for my file that > Emacs will help me write. An example is the following : of course, my > actual problem is not about generating English sentences; this is just > for illustration. > > (setq grammar '((sentence <- subject predicate) > (subject <- article noun) > (predicate <- verb))) > > I expect to generate functions that look like this: > > (defun sentence() > (........some stuff .........) > (subject) > (predicate) > (........some stuff again...)) > > What I want the system to do is to generate the function > automatically. So, I should have functions for sentence, subject and > predicate. I will of course hand-code the functions for article, noun > and verb. > > I don't want to write the above defun; I want to generate it by using > (setq sentence #'(lambda() ( (subject) (predicate)))). Of course, > instead of "sentence". I want to use (car x) or something like that by > reading the variable "grammar". > > Here is the problem: when I do this: > > (setq (car (expression that generates sentence) #'(lambda() (print > "hello"))) > > I get an error. > > But if I do a (setq x (car ... ) to get the sentence symbol and THEN > assign it, everything works. > > Is there something fundamental I am missing? You're near. First, remember that emacs lisp is a lisp-2. That means that a symbol can have both a function and a value. defun sets the function of the symbol. defvar (setf and setq) set the value of the symbol. (This is in opposition to scheme which is a lisp-1 and where you only need to assign a procedure value to a variable to define a function). So what do you want to generate? (defun sentence ...) or (setq sentence (lambda ....)) ? Also, something you might consider is that there is no package in emacs lisp, so whether you use the function slot or the value slot of these symbol, it is global. Imagine you want to edit an XML describing some graphic with lines and arrows at the beginning or the end of the lines. You could have have this kind of grammar: (define-grammar graphic-xml (graphic -> lines) (lines -> ) (lines -> line lines) (line -> beginning-of-line line-attributes end-of-lines) (beginning-of-line -> x y decoration) (end-of-line -> x y decoration)) Oops! You just redefined the emacs lisp functions beginning-of-line and end-of-line, and about 30% of the keypresses will now break... One solution would be to build composed symbol names. For example, the global functions and variables defined by ERC, the Emacs iRc Client all start with erc-. Another solution is to keep your generated functions in a hash-table indexed by the symbols. In this case, the hash-table defines in a way another namespace. Ok, so now let's address your main question. What you have is a list containing a grammar production like: ( -> ... ) and you want to get a _list_ like: (defun () () ... ()) Well, there's really no difficulty. I'm sure you could easily do it. if defun gives you difficulties, try to generate this list instead: (donald mickey () ... ()) Here it is: (defun generate-production (prod) (destructuring-bind (name separator &rest items) prod (list* 'defun name '() (mapcar (lambda (item) (list item)) items)))) (generate-production '(sentence <- subject predicate)) --> (defun sentence nil (subject) (predicate)) On the other hand, if you want to put these function into a hash-table, you could write: (defun generate-rhs (items) (list* 'lambda '() (mapcar (lambda (item) (list item)) items))) (defun store-production (grammar production) (destructuring-bind (name separator &rest items) production (setf (gethash name grammar) (byte-compile (generate-rhs items))))) (setq grammar (make-hash-table)) (store-production grammar '(sentence <- subject predicate)) We can call the function associated with sentence with: (funcall (gethash 'sentence grammar)) Note that we don't generate a setf, we just generate the (lambda ...) compile it, and put the resulting compiled function into the hash-table. As for: > (setq (car (expression that generates sentence) #'(lambda() (print > "hello"))) yes, you can use set in this situation: (destructuring-bind (name separator &rest items) production (set name (byte-compile `(lambda () ,@(mapcar 'list items))))) or, equivalently setf symbol-value: (destructuring-bind (name separator &rest items) production (setf (symbol-value name) (byte-compile `(lambda () ,@(mapcar 'list items))))) but it's probably better to but these function in a hash-table than in the value slots of the symbols. Instead of writting deep expressions such as: (list 'lambda '() (append '(save-excursion) (list (list 'insert '"<" (string name) '">")) forms (list (list 'insert '"")))) you can use backquote and comma to write it more easily: `(lambda () (save-excursion (insert "<" ,(string name) ">") ,@forms (insert ""))) so for example, you could write: (defun make-name (name) (intern (format "xml-insert/%s" name))) (defun generate-production (prod) (destructuring-bind (name separator &rest items) prod `(defun ,(make-name name) () (insert ,(format "<%s>" name)) ,@(mapcar (lambda (item) `(,(make-name item))) items) (insert ,(format "" name))))) (generate-production '(sentence <- subject predicate)) --> (defun xml-insert/sentence nil (insert "") (xml-insert/subject) (xml-insert/predicate) (insert "")) Finally, emacs is not modal. It would not be very emacs-like to do M-x xml-insert/document RET and to be prompted for half a hour to insert a whole document. Instead, you could do something like customize-variable. Try for example M-x customize-variable RET lisp-source-modes RET Most of the buffer is read-only, and there are left some area you can edit. There are some buttons, to insert or remove repeatitive areas. You could have a look at the sources of customize-variable to see how it's done and implement your structural editor like this. -- __Pascal Bourguignon__ http://www.informatimago.com/ THIS IS A 100% MATTER PRODUCT: In the unlikely event that this merchandise should contact antimatter in any form, a catastrophic explosion will result.