(archive 'newLISPer)

October 29, 2007

Rabbit season

Filed under: newLISP — newlisper @ 09:30

When you’ve used the little newLISP debugger to hunt down the bugs inside the functions, you might want to take a step back and observe the flow of your program, watching the data hop from one function to another. Here’s a useful technique I learnt from newLISP guru Fanda.

Using newLISP macros, you can – to some extent – change the way the language operates. (Probably many other programming languages let you do this too, not just those in the Lisp family, although I’m not familiar with any other language, so I wouldn’t know!) The following macro modifies the action of the define function which you normally use to build your code.

Put it at the beginning of your script to have all your function definitions modified:

(define-macro (my-define:my-define @farg) 
  (set (@farg 0) 
    (letex (@fn (@farg 0) 
            @arg (rest @farg) 
            @arg-p (cons 'list 
              (map 
                (fn   (@x) (if (list? @x) (first @x) @x)) 
                (rest @farg))) 
            @body (cons 'begin (args))) 
       (lambda @arg 
         (println 
          "\n[" '@fn   ; function name
          "]\n\t params: " 
          @arg-p     ; function's parameters
          "\n\t args: " 
          (args)     ; function's arguments 
          "\n\t[" '@fn  "] result: " 
          @body      ; result of function
         )))))
  (constant (global 'newLISP-define) define)
  (constant (global 'define) my-define)

Starting at the last line: we can use constant to make the word define point to any function or macro we like, so after defining a replacement for define, called my-define, we swap out the standard version. Before doing that, it’s prudent to keeping a link to the standard version!

After defining this macro, this code runs when newLISP next encounters a define. The argument – referred to here as @farg – contains the function name, the function’s arguments, and the expressions in the function body. In newLISP, data can be code, and code can be data.

The @farg argument is the body of the function definition that you’ve written that’s passed – unevaluated – to the macro.

The body of the macro consists of a single statement, and it’s effectively (set 'function-name arguments body), equivalent to (define function-name arguments body). The letex function combines both let and expand, and expands the symbols and assigns them to local symbols.

The rest of the macro is mainly concerned with organizing the contents of the original function definition and building a new function from them. But there’s one addition: there’s a println function inserted into the function definition, for printing out the details of the function’s parameters and results.

In action, a couple of functions defined like this:

(define (average a b c)
  (div (add a b c) 3))
(define (action n1 n2 n3)
  (average (mul n1 2) (mul n2 3) (mul n3 4)))
(action 2.1 4.4 6.8)

produce this trace:

[action]
   params: (2.1 4.4 6.8)
   args: ()
  [action] result: 
[average]
   params: (4.2 13.2 27.2)
   args: ()
  [average] result: 14.86666667
14.86666667

The output lets you watch the data being passed to and returned by each function. I’ve found it very useful, because you can find the moment when the data gets mangled.

The @ signs are used here simply to produce symbol names that are unlikely to clash with symbol names used elsewhere. You can’t define functions that use some of the symbol names used in this macro:

(define (f @arg-p)
    (println @arg-p))

(f "cool")

symbol is protected : (list @arg-p)
called from user defined function f

It’s at this point that my brain begins to hurt, so that’s enough macros for now.

Comment from cormullion

Lutz says we don’t need the duplicated my-define:my-define in the macro name…

Advertisements

Leave a Comment »

No comments yet.

RSS feed for comments on this post.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Blog at WordPress.com.

%d bloggers like this: