Arc Forumnew | comments | leaders | submitlogin
destructuring the quotation symbol
4 points by drcode 6136 days ago | 10 comments
Looking at my library of macros, I find that about half of them are used simply to quote parameters. I spend a lot of time writing dsl logic, where this is frequently needed, but I suspect others have many of these macros as well.

For example, suppose you need a convenience function for adding a prefix to a symbol:

  > (= x 'bar)
  > (addpref foo x)
  foobar
This is how I would write this command:

  (def addpref1 (a b)
    (sym (string a b)))

  (mac addpref (a b)
    `(addpref1 ',a ,b))
The goal here is to minimize the complexity of the macro by delegating everything besides the quotation of the parameter to a helper function. But having macros just to quote parameters feels a bit like overkill and makes for bulky code. It also pollutes the namespace with a helper function name. Couldn't there be a better way?

I present my solution- A version of "def" enhanced to allow destructuring of quotation marks!

  (mac defq (nam parms . body)
    (let unquoted [and (acons _) (is 'unquote car._)]
      (if (find unquoted parms)
	  (with (nuparms (map [if unquoted._
	  			cadr._
	  			_]
			    parms)
	       zparms (map [if unquoted._
			       (list 'quote _)
			       (list 'unquote _)]
			   parms)
	       x (uniq))
	  `(do (def ,x ,nuparms
		 ,@body)
	       (mac ,nam ,nuparms
		 (,'quasiquote (,x ,@zparms)))))
	`(def ,nam ,parms ,@body))))
This command supports everything "def" can do:

  > (defq mycons (a b)
          (cons a b))
  #<procedure: mycons>
  > (mycons 1 2)
  (1 . 2)
The magic of this command is that quotes marks can be "unquoted" in the parameter list- If you think it through, it makes perfect sense to allow this. Here is a version of addpref defined with defq:

  > (defq addpref (,a b)
           (sym (string a b)))
  #3(tagged mac #<procedure>)
Notice that defq detected the unquoting of a parameter and therefore generated a macro instead of a function. Let's try to use this command now:

  > (= x 'bar)
  > (addpref foo x)
  foobar
...and there you go: It behaves and looks just like a regular function created with "def", but one of its parameters has been magically quoted!

There is no technical or performance limitation that would prevent including this kind of functionality in the standard "def" command, if this was to prove useful enough to be justified. This initial version only supports unquoting of parameters without other types of destructuring, but it would be relatively straight-forward to extend this approach to supporting unquoting along with arbitrary destructuring.

In fact, it could even (if one were crazy enough to implement this) be used to unify "mac" and "def" into a single operation- and I think it might be a pretty elegant unified command...



4 points by almkglor 6136 days ago | link

Looks like the old nprocedure protocol used in really old lisps to me. ^^

The problem is that macros are not functions, in spite of having the same syntax. How would addpref react if it was passed to map? By quoting map's variable?

-----

3 points by drcode 6136 days ago | link

You are right there'd be no way to map with addpref. However, doing it in the usual way wouldn't allow this either, so nothing is lost.

-----

1 point by kens1 6136 days ago | link

I took a look at arc.arc, and I didn't see any macros there that would be helped by destructuring quotation. I did notice that the macros: w/stdin, w/stdout, thread, atomic solely exist to wrap body code in a lambda (fn) expression. Maybe that sort of wrapping would be useful to add to defq?

-----

1 point by drcode 6135 days ago | link

Yes, most of the axiomatic stuff in arc.arc probably would not benefit from this I think. I can see a couple, such as "deftem", that could probably make use of this.

-----

1 point by cchooper 6136 days ago | link

I think it's a neat idea (it really does bug me when I write really short macros that just delegate) but I agree with almkglor that mixing functions and macros isn't good. I'd prefer that defq just always returned a macro.

Don't want to be too critical though. It's a great idea and could definitely make a few programs shorter.

-----

4 points by drcode 6136 days ago | link

I admit that mixing macros and functions is risky business. A case could be made for having defq always return macros.

-----

2 points by tel 6135 days ago | link

Isn't the point of Arc to always enthusiastically jump into risky business?

-----

1 point by drcode 6135 days ago | link

my thoughts exactly.

-----

1 point by akkartik 6136 days ago | link

Unifying def and mac sounds akin to perpetual motion :)

Another crazy idea: use quoting to implement currying. When a function doesn't get enough arguments it simply evaluates what it gets and quotes what it doesn't get. When it has enough it evaluates the body.

Heh, I'm now expecting to find out that that is indeed how currying is implemented. Just replace quoting with some internal tag/annotation.

-----

1 point by drcode 6136 days ago | link

I actually proposed something similar a month ago with regards to currying (My idea was that "unwanted" parameters get curried by putting an underscore in their place in the param list. You idea may work even better- haven't thought through the details yet)

-----