News for hackers. Stuff that matters.
Re:A Codewalk for Arc3's first-class(runtime) macros by dpkendal on Tuesday May 29, 2012 @01:23AM (#4036081)
Actually macros are not first-class in Arc (though they are stored in the same namespace as everything else, unlike in Scheme). You can't return one from a function, for instance. They were a feature of early implementations (they're mentioned in various places in old stuff related to its development), but they were cut before the first release. When I asked pg why he removed them, his answer was:

> I don't remember. It was either because they were useless or confusing or intellectually inelegant.

Having experienced first-class macros in my own Lisp implementation, I'm inclined to agree. Though there are various promises of efficient implementations scattered through the internet, nobody actually goes into enough detail to explain it. Non-first-class macros are the way to go for efficiency, at least, and first-class macros themselves are fairly useless.

Re:A Codewalk for Arc3's first-class(runtime) macros by zck on Tuesday May 29, 2012 @02:25AM (#4036200)
Well, here's an example where not having first-class macros is confusing:

in takes any number of arguments, and returns whether the first argument is repeated in the rest of them:

  arc> (in 2 1 2 3)
  t
  arc> (in 0 1 2 3)
  nil
Ok, let's say I have a list, and I want to find out whether something is in it:

  arc> (apply in 2 (list 1 2 3))
  Error: "Function call on inappropriate object #(tagged mac #<procedure: in>) (0 1 2 3)"
Oh dear. That's not right.

The solution, at least in Arc, is to use mem:

  arc> (mem 2 (list 1 2 3))
  (2 3)
It returns the first sub-list of its second argument such that the car of the returned list is the element searched for -- or 'nil if the element isn't in the list. So yes, you can make it work, in this case. But it's surely more confusing than having (apply in 2 (list 1 2 3)) work.
Re:A Codewalk for Arc3's first-class(runtime) macros by akkartik on Tuesday May 29, 2012 @03:43AM (#4036422)
Oh you picked a doozie. Apply won't work on macros even if you have first-class macros. Even kernel says, "apply expects an applicative." I spent weeks understanding why. The reason has to do with apply's special status as a dual of eval, and the fact that macros implicitly eval their result in the caller's lexical scope. Here's an example to think about:

  (mac foo(a b) `(cons ,a ,b))
  (apply foo '(1 (2 3)))
  => (cons 1 (2 3))
  => error: 2 is not a function
Further discussion (more than you could ever want): http://arclanguage.org/item?id=15659; http://arclanguage.org/item?id=15907
Re:A Codewalk for Arc3's first-class(runtime) macros by Patient0 on Tuesday May 29, 2012 @04:53AM (#4036578)
I guess the alternative would be to define "apply" as a macro which evals the cons of its first argument and the other list of arguments...
Re:A Codewalk for Arc3's first-class(runtime) macros by akkartik on Tuesday May 29, 2012 @12:17PM (#4038195)
I addressed this approach at the top of the second link: http://arclanguage.org/item?id=15907

Basically you'd have to:

1. eval the list

2. cons the macro to the list, eval to yield the macroexpansion

3. implicitly eval the macroexpansion -- but not eval the elements of the spliced in list because they've already been eval'd once.

Step 3 throws a spanner in the works.

So you might say, fine, let's quote all the elements of the spliced in list. And that'll seem to work for the previous example, but you'll eventually run into an example like this:

  (apply = '(x 3))
  => (= 'x '3)
  => error: can't assign to (quote x)
So you have to perform step 3 without actually inserting a literal quote. I gave up at this point.
Re:A Codewalk for Arc3's first-class(runtime) macros by Patient0 on Tuesday May 29, 2012 @12:41PM (#4038331)
Ah I see.

I've started implementing a Lisp interpreter in C# and I also was going along the path of making everything "first class" by using f-expressions where appropriate. So far my only actual f-expressions are "lambda" and "if" - everything else is bootstrapped as macros or functions.

My "apply" currently expects a function but I was toying with making it "eval" the cons macro... but then "apply" has to become an f-expression instead of just a plain normal function which seemed inelegant so I left it as a function that requires a function.

Reading your story... I think I'll leave it permanently side-stepped!! :-)

Re:A Codewalk for Arc3's first-class(runtime) macros by akkartik on Tuesday May 29, 2012 @12:57PM (#4038430)
Nice to meet ya! I've been working on a lisp as well: http://github.com/akkartik/wart#readme
Re:A Codewalk for Arc3's first-class(runtime) macros by akkartik on Saturday June 02, 2012 @02:03AM (#4057218)
BTW, in case you see this: I solved the problem for a large subset of macros. Details: http://arclanguage.org/item?id=16378
Re:A Codewalk for Arc3's first-class(runtime) macros by wsxiaoys on Tuesday May 29, 2012 @01:44AM (#4036117)
> You can't return one from a function, for instance.

Actually you can, for example:

    (assign macro-maker 
      (fn (x)
        (annotate 'mac (fn (y) `(cons ,x ',y)))))

    (assign m1 (macro-maker 1))

    (disp (m1 a)) ; print (1 . a)

    (macex '(m1 3)) ; print (cons 1 (quote a))
Above code are tested in tryarc.org.

> Non-first-class macros are the way to go for efficiency, at least, and first-class macros themselves are fairly useless.

It's true that non-first-class macros can be more efficiency. But first class macros can benefit from it's nature - a lexical function with environment. Construct such macros can be fancy.