From: Christian Haselbach
Subject: Tiny list interpreter
Date: 
Message-ID: <e6nfn9$gj3$1@online.de>
Hello,

I want to write a function to interpret a list with a small, predefined 
set of commands. For the sake of simplicity lets assume that each 
command evaluates to a value and the result of the interpretation shall 
be the list of values.

For now, I came up with this:

(let ((cmds
        (list (cons 'foo #'+)
	     (cons 'bar (lambda (x) (+ 2 x))))))
   (defun myinterp (prg)
     (loop for (cmd . args) in prg
	  for fcmd = (cdr (assoc cmd cmds))
	  unless fcmd do (error "command ~S not found" cmd)
	  collect (apply fcmd args))))

This works just fine, but I guess that there is a better way to get the 
appropriate function and evaluate it with the arguments.

Any hints or comments?

Regards,
Christian

From: Pascal Bourguignon
Subject: Re: Tiny list interpreter
Date: 
Message-ID: <87zmggwsy3.fsf@thalassa.informatimago.com>
Christian Haselbach <······@muon.de> writes:

> Hello,
>
> I want to write a function to interpret a list with a small,
> predefined set of commands. For the sake of simplicity lets assume
> that each command evaluates to a value and the result of the
> interpretation shall be the list of values.
>
> For now, I came up with this:
>
> (let ((cmds
>        (list (cons 'foo #'+)
> 	     (cons 'bar (lambda (x) (+ 2 x))))))
>   (defun myinterp (prg)
>     (loop for (cmd . args) in prg
> 	  for fcmd = (cdr (assoc cmd cmds))
> 	  unless fcmd do (error "command ~S not found" cmd)
> 	  collect (apply fcmd args))))
>
> This works just fine, but I guess that there is a better way to get
> the appropriate function and evaluate it with the arguments.

Define "better".

> Any hints or comments?

You could write a compiler.

(eval-when (:compile-toplevel :load-toplevel :execute)
  (defparameter *command-map* (make-hash-table)))

(defmacro defcommand (name lispfun)
  `(progn (setf (gethash ',name *command-map*) ',lispfun)
          ',name))

(defcommand foo +)
(defcommand bar (lambda (x) (+ 2 x)))

(defun compile-program (prg)
  `(lambda ()
     ,@(mapcar
          (lambda (cmd-args)
              (destructuring-bind (cmd . args) cmd-args
                 (let ((fun (gethash cmd *command-map*)))
                    (if fun
                      `(,fun ,@args)
                      (error "command ~S not found in ~S" cmd cmd-args)))))
           prg)))

(defparameter *pgm* (compile nil
                     (print (compile-program '((foo 1 2 3) (bar 4))))))
(funcall *pgm*)

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
        Un chat errant
se soulage
        dans le jardin d'hiver
                                        Shiki
From: Pascal Bourguignon
Subject: Re: Tiny list interpreter
Date: 
Message-ID: <87hd2nvapy.fsf@thalassa.informatimago.com>
Pascal Bourguignon <···@informatimago.com> writes:

> Christian Haselbach <······@muon.de> writes:
>
>> Hello,
>>
>> I want to write a function to interpret a list with a small,
>> predefined set of commands. For the sake of simplicity lets assume
>> that each command evaluates to a value and the result of the
>> interpretation shall be the list of values.
>>
>> For now, I came up with this:
>>
>> (let ((cmds
>>        (list (cons 'foo #'+)
>> 	     (cons 'bar (lambda (x) (+ 2 x))))))
>>   (defun myinterp (prg)
>>     (loop for (cmd . args) in prg
>> 	  for fcmd = (cdr (assoc cmd cmds))
>> 	  unless fcmd do (error "command ~S not found" cmd)
>> 	  collect (apply fcmd args))))
>>
>> This works just fine, but I guess that there is a better way to get
>> the appropriate function and evaluate it with the arguments.
>
> Define "better".
>
>> Any hints or comments?
>
> You could write a compiler.
>
> (eval-when (:compile-toplevel :load-toplevel :execute)
>   (defparameter *command-map* (make-hash-table)))
>
> (defmacro defcommand (name lispfun)
>   `(progn (setf (gethash ',name *command-map*) ',lispfun)
>           ',name))
>
> (defcommand foo +)
> (defcommand bar (lambda (x) (+ 2 x)))
>
> (defun compile-program (prg)
>   `(lambda ()
>      ,@(mapcar
>           (lambda (cmd-args)
>               (destructuring-bind (cmd . args) cmd-args
>                  (let ((fun (gethash cmd *command-map*)))
>                     (if fun
>                       `(,fun ,@args)
>                       (error "command ~S not found in ~S" cmd cmd-args)))))
>            prg)))
>
> (defparameter *pgm* (compile nil
>                      (print (compile-program '((foo 1 2 3) (bar 4))))))
> (funcall *pgm*)

Of course, since you want to collect the results, the compiler should
generate code as follow:

(defun compile-program (prg)
   `(lambda ()
      (list         ; add this!
      ,@(mapcar
           (lambda (cmd-args)
               (destructuring-bind (cmd . args) cmd-args
                  (let ((fun (gethash cmd *command-map*)))
                     (if fun
                       `(,fun ,@args)
                       (error "command ~S not found in ~S" cmd cmd-args)))))
            prg)))) ; and a closing parenthesis

(defparameter *pgm* (compile nil
                     (print (compile-program '((foo 1 2 3) (bar 4))))))
prints: (LAMBDA NIL (LIST (+ 1 2 3) ((LAMBDA (X) (+ 2 X)) 4))) 
--> *pgm*

(funcall *pgm*) --> (6 6)



Sorry for the confusion.

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
-----BEGIN GEEK CODE BLOCK-----
Version: 3.12
GCS d? s++:++ a+ C+++ UL++++ P--- L+++ E+++ W++ N+++ o-- K- w--- 
O- M++ V PS PE++ Y++ PGP t+ 5+ X++ R !tv b+++ DI++++ D++ 
G e+++ h+ r-- z? 
------END GEEK CODE BLOCK------
From: vanekl
Subject: Re: Tiny list interpreter
Date: 
Message-ID: <1150280392.363781.288340@y41g2000cwy.googlegroups.com>
Christian Haselbach wrote:
> Hello,
>
> I want to write a function to interpret a list with a small, predefined
> set of commands. For the sake of simplicity lets assume that each
> command evaluates to a value and the result of the interpretation shall
> be the list of values.
>
> For now, I came up with this:
>
> (let ((cmds
>         (list (cons 'foo #'+)
> 	     (cons 'bar (lambda (x) (+ 2 x))))))
>    (defun myinterp (prg)
>      (loop for (cmd . args) in prg
> 	  for fcmd = (cdr (assoc cmd cmds))
> 	  unless fcmd do (error "command ~S not found" cmd)
> 	  collect (apply fcmd args))))
>
> This works just fine, but I guess that there is a better way to get the
> appropriate function and evaluate it with the arguments.
>
> Any hints or comments?
>
> Regards,
> Christian

if you want continuations, Guy Steele's "FOO" language is short and
eye-opening. http://fresh.homeunix.net/~luke/misc/foo1.lisp

Lou Vanek
--
Opportunity is missed by most people because it is dressed in overalls
and looks like work.          Thomas A. Edison
From: Christian Haselbach
Subject: Re: Tiny list interpreter
Date: 
Message-ID: <e6q0qh$tgn$1@online.de>
vanekl wrote:
> if you want continuations, Guy Steele's "FOO" language is short and
> eye-opening. http://fresh.homeunix.net/~luke/misc/foo1.lisp

Thank you and Pascal for your responses. Both replies gave me some food 
for thoughts. And I think I know now how I want to solve the problem.

JFTR: I was not (necessarily) looking for continuations. The particular 
problem is a path description that has to be evaluated with different 
rules, e.g., for drawing strokes along the path or filling it. The idea 
was to have an s-expression of the pass like ((move (5 10)) (line (20 
15)) and evaluate it. I have been so vague in my first post, because I 
was trying to have a broader look at it.

Regards,
Christian