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
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
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------
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