Examples of what Lisp's macros can be used for

后端 未结 8 919
自闭症患者
自闭症患者 2020-12-24 05:56

I\'ve heard that Lisp\'s macro system is very powerful. However, I find it difficult to find some practical examples of what they can be used for; things that would be diffi

8条回答
  •  天涯浪人
    2020-12-24 06:47

    Anything you'd normally want to have done in a pre-processor?

    One macro I wrote, is for defining state-machines for driving game objects. It's easier to read the code (using the macro) than it is to read the generated code:

    (def-ai ray-ai
      (ground
       (let* ((o (object))
              (r (range o)))
         (loop for p in *players*
               if (line-of-sight-p o p r)
               do (progn
                    (setf (target o) p)
                    (transit seek)))))
      (seek
       (let* ((o (object))
              (target (target o))
              (r (range o))
              (losp (line-of-sight-p o target r)))
         (when losp
           (let ((dir (find-direction o target)))
             (setf (movement o) (object-speed o dir))))
         (unless losp
           (transit ground)))))
    

    Than it is to read:

    (progn
     (defclass ray-ai (ai) nil (:default-initargs :current 'ground))
     (defmethod gen-act ((ai ray-ai) (state (eql 'ground)))
                (macrolet ((transit (state)
                             (list 'setf (list 'current 'ai) (list 'quote state))))
                  (flet ((object ()
                           (object ai)))
                    (let* ((o (object)) (r (range o)))
                      (loop for p in *players*
                            if (line-of-sight-p o p r)
                            do (progn (setf (target o) p) (transit seek)))))))
      (defmethod gen-act ((ai ray-ai) (state (eql 'seek)))
                (macrolet ((transit (state)
                             (list 'setf (list 'current 'ai) (list 'quote state))))
                  (flet ((object ()
                           (object ai)))
                    (let* ((o (object))
                           (target (target o))
                           (r (range o))
                           (losp (line-of-sight-p o target r)))
                      (when losp
                        (let ((dir (find-direction o target)))
                          (setf (movement o) (object-speed o dir))))
                      (unless losp (transit ground)))))))
    

    By encapsulating the whole state-machine generation in a macro, I can also ensure that I only refer to defined states and warn if that is not the case.

提交回复
热议问题