Arc Forumnew | comments | leaders | submitlogin
2 points by fallintothis 4128 days ago | link | parent

Ah, there's an idea. Never thought to use the technique for avoiding slashed names. It makes sense. When you start writing Lisp macros, you quickly notice that you can use uninterpreted symbols as syntax. I remember way back when (I think probably when I first read Comprehending Monads by Philip Wadler), I toyed with writing a list macro to support not just the usual (list x), but also list comprehensions, like

  (list (+ x 1) for x in xs if (> x 5))
That was a fun one. I don't think I have the code for it lying around anywhere. Not that it'd be hard to write again---it translates straightforwardly into maps & keeps. I suppose the end of this slippery slope would be the loop macro (http://clisp.hg.sourceforge.net/hgweb/clisp/clisp/file/tip/s...). Not necessarily a bad thing, if you aren't eschewing specialized syntax anyway.

Although, if the sole purpose here is to do away with slashed names, the only real place they're used in Arc is to shorten with- to w/.

  arc> (keep [find #\/ (string _)] (keys sig))
  (w/bars w/rlink w/table when-umatch/r w/uniq w/stdin w/stdout w/outstring w/appendfile w/socket w/outfile w/link w/instring w/infile w/link-if)
So, though the mechanism by which it works is more general, you could stay disciplined by focusing on with instead of mac2 stuff. Something like the following, only in wart instead of Arc. :)

  ; Make 'let not rely on 'with, so it won't dispatch on special keywords by
  ; mistake

  (mac let (var val . body)
    `((fn (,var) ,@body) ,val))

  (= special-with* (table))

  (mac with args
    (aif (special-with* (car args))
         (apply it (cdr args))
         (let (parms . body) args
           `((fn ,(map1 car (pair parms))
               ,@body)
             ,@(map1 cadr (pair parms))))))

  (mac withify (keyword parms . body) ; for want of a better name...
    `(= (special-with* ',keyword) (fn ,parms ,@body)))

  (withify uniq (vars . body)
    `((fn ,vars ,@body) ,@(map1 [uniq] vars)))

  (withify tmpfile (f . body)
    `(let ,f (tmpfile)
       (before (system:join "rm " ,f)
         ,@body)))

  arc> (macex '(with (x 1 y 2) (+ x y)))
  ((fn (x y) (+ x y)) 1 2)
  arc> (macex '(with uniq (x y) (do-something-with x y)))
  ((fn (x y) (do-something-with x y)) gs1740 gs1741)
  arc> (macex '(with tmpfile foo (writefile 'stuff foo)))
  ((fn (foo) (before (system:join "rm " foo) (writefile (quote stuff) foo))) (tmpfile))
I'm not sure if that alleviates your keyword argument woes. It makes the definitions of with variants explicit without needing sigils or whatnot (because what else are you going to pass as the first argument to withify?). But, it also doesn't get along so well (aesthetically) with Scheme-style name-goes-in-arglist definitions.


1 point by akkartik 4128 days ago | link

Yes, that feels like a very complete summary of the tradeoffs. I'm surprised I hadn't noticed that what I was doing was similar to the loop macro!

-----