help-gnu-emacs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Using setq to obtain a symbol from a list, so that I can assign a f


From: Pascal Bourguignon
Subject: Re: Using setq to obtain a symbol from a list, so that I can assign a function to it
Date: Thu, 24 Apr 2008 00:14:04 +0200
User-agent: Gnus/5.1008 (Gnus v5.10.8) Emacs/22.1 (gnu/linux)

srinik001@hotmail.com writes:
> Thanks for the tip. Now, it does not throw an error. But I still don't
> get what I want. Here is what I did:
>
> (setq grammar '((sentence ::= subject predicate)
>               (subject ::= article noun)
>               (predicate ::= verb)))
> --> This of course worked. I could see the individual elements, their
> car's and cdr's etc.

Also, you shouldn't think it terms of car and cdr here.  Don't define
your grammar as plain lists like this. 

Define it as a grammar!

(define-grammar simple-english 
   :start-symbol sentence
   :productions ((sentence  ::= subject predicate)
                 (subject   ::= article noun)
                 (predicate ::= verb)))

(Of course, you could represent such grammar exactly as you did, with
a simple list of lists, but it would be better to define grammars as
CLOS  objects (or rather, CLOS-like objects, using eieio) or just
plain structures).

(require 'cl)

(defstruct grammar
   start-symbol
   non-terminals
   terminals
   productions
   (generators (make-hash-table)))

(defstruct production
   lhs
   rhs
   generator)
   
(defmacro* define-grammar (name &key (start-symbol nil start-symbol-p)
                                productions)
  `(progn
     (defvar ,name)
     (setf ,name
           (make-grammar
            :start-symbol ',(if start-symbol-p
                               start-symbol
                               (first (first productions)))
            :productions (list
                          ,@(mapcar
                             (lambda (prod-sexp)
                               (destructuring-bind (lhs sep &rest rhs)
                                   prod-sexp
                                 `(make-production
                                   :lhs ',lhs
                                   :rhs ',rhs
                                   :generator (lambda () (error "not generated 
yet")))))
                             productions))))
     (compute-terminals-and-non-terminals ,name)
     ',name))


(defun compute-terminals-and-non-terminals (grammar)
  (let ((non-terminals (mapcar (function production-lhs) 
                               (grammar-productions grammar)))
        (symbols   (mapcan (lambda (prod)
                              (copy-list (production-rhs prod)))
                           (grammar-productions grammar))))
     (setf (grammar-non-terminals grammar) non-terminals
           (grammar-terminals grammar)
             (remove-duplicates (set-difference symbols non-terminals)))
     grammar))


(defun grammar-symbol-generator (grammar symbol)
  (gethash symbol (grammar-generators grammar)))

(defun set-grammar-symbol-generator (grammar symbol new-generator)
  (setf (gethash symbol (grammar-generators grammar)) new-generator))

(defsetf grammar-symbol-generator set-grammar-symbol-generator)


(pprint
 (macroexpand '(define-grammar simple-english 
                :start-symbol sentence
                :productions ((sentence  ::= subject predicate)
                              (subject   ::= article noun)
                              (predicate ::= verb)))))
-->
(progn
  (defvar simple-english)
  (setf simple-english
        (make-grammar :start-symbol 'sentence :productions
                      (list (make-production :lhs 'sentence :rhs
                                             '(subject predicate)
                                             :generator #1=
                                             (lambda ()
                                               (error
                                                "not generated yet")))
                            (make-production :lhs 'subject :rhs
                                             '(article noun)
                                             :generator #1#)
                            (make-production :lhs 'predicate :rhs
                                             '(verb) :generator #1#))))
  (compute-terminals-and-non-terminals simple-english)
  'simple-english)




(define-grammar simple-english 
                :start-symbol sentence
                :productions ((sentence  ::= subject predicate)
                              (subject   ::= article noun)
                              (predicate ::= verb)))
--> simple-english

(grammar-terminals simple-english)
--> (verb noun article)

(grammar-non-terminals simple-english)
--> (sentence subject predicate)

(production-rhs (first (grammar-productions simple-english)))
--> (subject predicate)



> Then I defined the "leaf" level things:
>
> (defun article()
>   (insert "article"))
>
> (defun noun()
>   (insert "noun"))
>
> (defun verb()
>   (insert "verb"))
>
> Then I tried this:
>
> (dolist (x grammar)
>   (set (car x) (dolist (y (cdr (cdr x))) (funcall y)))
>
> It threw an error saying that it did not know what subject was. 

Well perhaps.  Whatever.

Perhaps you mean something like:

(let ((grammar simple-english))
  (dolist (terminal (grammar-terminals grammar))
    (setf (grammar-symbol-generator grammar terminal)
          (make-terminal-generator grammar terminal)))
  (dolist (prod (grammar-productions grammar))
     (setf (grammar-symbol-generator grammar (production-lhs prod))
           (make-non-terminal-generator grammar (production-rhs prod)))))

with:

(defun make-terminal-generator (grammar terminal)
  (byte-compile
     `(lambda ()
         (insert ,(symbol-name terminal))
         (insert " "))))

(defun make-non-terminal-generator (grammar rhs)
   (byte-compile
     `(lambda ()
        ,@(mapcar (lambda (item) 
                     `(funcall 
                        (or (grammar-symbol-generator
                                  ',grammar ',item)
                            (error "No generator for %S" ',item))))
                  rhs))))



If you insist, you can always implement all these abstraction using
cons car and cdr (but it might be more efficient, and simplier to use
defstruct or eieio defclass).


(funcall (grammar-symbol-generator simple-english 'sentence))
inserts:
article noun verb 



> Of
> course, the way the grammar was described in the list, it did not know
> that. So I tried reversing the grammar, thinking that if it went the
> other way, it would understand subject before it came to sentence. So,
> I tried this.
>
> (dolist (x (reverse grammar))
>   (set (car x) (dolist (y (cdr (cdr x))) (funcall y))))
>
> It still gave the same error! It seems that when it does a set
> operation, it forgets it in the next iteration of the loop.

Lisp-1 vs. Lisp-2.  See my first answer.


> I apologize if these are trivial questions, but while being *very*
> addictive, Lisp seems unlike anything else that I have done before;
> perhaps I need to study Lisp a lot more before giving myself exercises
> like these, by studying Pascal's reply more carefully - I need to look
> up many of the functions/terms he uses. For example, I don't really
> get the difference between the quoted and the unquoted - I know they
> are different but can't seem to be able to put my finger on the exact
> difference.

It's the same difference as in English.

   Pascal's name is written "Pascal". 

   (I'm writting about M. Blaise Pascal of course).

Anyways, the first "Pascal" in the above sentence, you interpret it,
by fetching from your memory your representation of M. Blaise Pascal:
you evaluate it to the value of Pascal (in that context).

The second "Pascal", you don't evaluate it. You take it letter for
letter, because I quoted it.  It represents itself, the word "Pascal".
What would be the translation in lisp of that sentence about Pascal?



It's the same in lisp:

   (let ((var 'var))
     (format "The value of the variable %S is %S" 'var var))
   --> "The value of the variable var is var"
Oops, this example is too much. ;-)


Let's try again:

   (let ((var '42))
     (format "The value of the variable %S is %S" 'var var))
   --> "The value of the variable var is 42"

In the call to format, the argument 'var is evaluated.  The special
operator quote returns its argument unevaluated.  Therefore var is not
evaluated and returned as is, var itself.  The last argument var is
evaluated too.  It's a symbol, so lisp tries to find its value.
There's a binding of the variable var to the value 42, so the result
is 42.  format is then called with as argument the string, the symbol
var and the fixnum 42.




Here how you could translate the sentence about Pascal:

(defstruct person name)
(defvar pascal (make-person :name 'pascal))
(eql (person-name pascal) 'pascal)
--> t

The variable pascal is bound to a person whose name is the symbol
pascal itself.


You should read this tutorial specific to emacs lisp:
http://www.gnu.org/software/emacs/emacs-lisp-intro/ 
and of course, browse alot the online documentation and the sources of
emacs lisp function.


But what you want to do involves plain lisp programming, so you could
also learn more, by studying Common Lisp (or at least parts of Common
Lisp that have equivalents or that are similar to emacs lisp).  For
general programming there is much more material to study Common Lisp
than emacs lisp.  There are some significant differences between the
two lisps, but if you know how to program in Common Lisp, you should
be able to program in emacs lisp easily (Common Lisp being a richer
programming language, you will learn all the notions you have in emacs
lisp).  

Practical Common Lisp       
http://www.gigamonkeys.com/book/

Common Lisp: A Gentle Introduction to Symbolic Computation
http://www-cgi.cs.cmu.edu/afs/cs.cmu.edu/user/dst/www/LispBook/index.html
http://www.cs.cmu.edu/~dst/LispBook/


See also:

http://www.cliki.net/Education
http://www.cliki.net/Online+Tutorials
http://www.cliki.net/Lisp%20books


-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

PUBLIC NOTICE AS REQUIRED BY LAW: Any use of this product, in any
manner whatsoever, will increase the amount of disorder in the
universe. Although no liability is implied herein, the consumer is
warned that this process will ultimately lead to the heat death of
the universe.


reply via email to

[Prev in Thread] Current Thread [Next in Thread]