Arc Forumnew | comments | leaders | submitlogin
2 points by Pauan 5129 days ago | link | parent

"You might already know this (search for "AST" at http://arclanguage.org/item?id=13079), but I'm irked by special forms like 'assign or 'if too."

Yeah, I don't like those either. In fact, I was thinking about making `fn` a macro in PyArc. Also, if I can, I plan to allow programs to shadow things like `assign` and other special forms:

  (def foo (bar assign)
    (= bar "something"))

  (foo) -> error, because = uses assign, but assign is nil
I've also tried to keep the number of special forms in PyArc to an absolute minimum. Right now, there's quote, quasiquote, if, fn, assign, and apply. I hope to get rid of apply, and possibly fn.

The only way I can see to get rid of if, assign, quote, and quasiquote would be to create a third "function" type: it behaves like a function, so it's evaluated at run time, but it doesn't evaluate it's arguments, so it's basically a function/macro hybrid.

Haha, I just had a crazy idea. Make (fn) desugar into the special hybrid form, but have it evaluate all it's arguments. Then there would only be two function types, and (fn) would be a thin wrapper around one of them. I should be able to get rid of all the special forms then, leaving only functions and macros (which are just annotated functions anyways).

---

"I think 'o is a place where neither sacrifice is necessary (neither giving up (o b c) destructuring nor giving up 'o as a variable name)."

But you do give up (o a b) destructuring:

  (def foo ((o a 1) (o b a)) (list a b))

  (foo '(1 2 3) '(4 5 6)) -> ((1 2 3) (4 5 6))
Unless of course you're talking about ab/using ssyntax like .o, in which case you're not really using (o a b) anymore, nor would it work if ssyntax is expanded at read time.

Thus, it has the same gotcha as (= a b), which is that you can't use o as the first element when destructuring. By the way, I mentioned earlier that I could treat escaped symbols differently:

  (def foo ((|=| a b)) (list = a b))

  (foo '(1 2 3)) -> (1 2 3)
I think this approach would be better than using ssyntax, because || already means "escape this thing", so we don't need to invent new syntax for it. Not sure if I'll go that route, but it is an option.


1 point by rocketnia 5129 days ago | link

You have 'apply as a special form? In most Schemes it's a function. :)

You can definitely implement 'quasiquote and 'if as macros.

That leaves 'quote, 'fn, and 'assign. Those are all pretty fundamental. While you could make them macros, there's pretty much nothing to turn them into, unless you go for the tagged type route.

---

"The only way I can see to get rid of if, assign, quote, and quasiquote would be to create a third "function" type: it behaves like a function, so it's evaluated at run time, but it doesn't evaluate it's arguments, so it's basically a function/macro hybrid."

Hey, look, fexprs. XD Every sufficiently long Arc Forum topic seems to get around to them at some point. :-p

Since you're writing an interpreter, fexprs are a natural thing to do. They have certain elegance advantages over classical macros, since you can avoid special forms altogether, and programmers can (re)define their fexprs after the places they use them. The main disadvantage is that they're much harder to efficiently compile--not an issue for an interpreter.

---

"Haha, I just had a crazy idea. Make (fn) desugar into the special hybrid form, but have it evaluate all it's arguments. Then there would only be two function types, and (fn) would be a thin wrapper around one of them. I should be able to get rid of all the special forms then, leaving only functions and macros (which are just annotated functions anyways)."

Kernel, the most promising design I've seen for an efficient fexpr language (er, with lexical scope; sorry, PicoLisp) does the opposite: Functions are annotated fexprs. All forms are applied in exactly the same way, but functions take the extra step of evaluating their arguments. (FYI, Kernel calls functions "applicatives" and fexprs "operatives.") The one thing about Kernel is that it's kinda vaporware....

There was recently an Arc Forum topic about Kernel: http://arclanguage.org/item?id=13354

Here are a couple of topics about PicoLisp while I'm at it: http://arclanguage.org/item?id=1110 http://arclanguage.org/item?id=10829

Eight's another fexpr language with lexical scope. Like Kernel, it isn't quite complete, but at least it's developed in the open on GitHub. (Hi diiq!) There's a very old topic on Eight here: http://arclanguage.org/item?id=10719

Recently, like a few months ago, diiq came back to Eight and reimplemented it in JavaScript. I've been too busy to bother with it yet, but it oughta be awesome if it's both similar to Arc and runnable in a browser.

---

"Unless of course you're talking about ab/using ssyntax like .o, in which case you're not really using (o a b) anymore, nor would it work if ssyntax is expanded at read time."

That's exactly the kind of thing I'm talking about. :) That's a solution I'm satisfied with for official Arc, but I'm confident there'd be at least some solution for PyArc that I liked better than 'o. It may just be too early to identify it.

---

"By the way, I mentioned earlier that I could treat escaped symbols differently: [...] I think this approach would be better than using ssyntax, because || already means "escape this thing", so we don't need to invent new syntax for it. Not sure if I'll go that route, but it is an option."

Well, I'm not sure what s-expressions you consider the 'def macro to see as input. If you manage to be consistent about that, and if you don't actually need to use the || in practice too much, then it's an idea I could get behind.

-----

1 point by Pauan 5129 days ago | link

It's both a function and a special form. Yes, it's weird. Yes, I hope to change it.

I don't see how `if` could be implemented as a macro. Consider this case:

  (def foo (a) (if a 1 2))
The `if` form needs to be evaluated every time the foo function is run, and then return either 1 or 2, depending on what 'a is. Keep in mind this is Python, so I can't have `if` desugar to `cond`. :P

---

Yeah, that's what I was talking about: have `fn` be a fexpr that returns functions that are annotated with type 'fn. And since macros are just functions with type 'fn, that would mean that everything in PyArc boils down to fexprs.

I didn't realize that what I described was fexprs, but in hindsight I probably should have. I actually messed around with NewLisp for a bit; they use fexprs. I prefer Arc's macro system, since I don't think NewLisp has quasiquote/unquote, which made certain things more verbose than they should have been.

However, the ability to have everything desugar to fexprs is appealing, especially since I no longer need special forms hardcoded into eval. PyArc will still have normal functions and macros, of course. They'll just be fexprs underneath. :P

-----

1 point by rocketnia 5129 days ago | link

Here's a version of 'if that depends only on a built-in function and a built-in macro:

  (def fn-if (condition then else)
    ((if condition then else)))
  
  (mac if body
    (whenlet (first . rest) body
      (iflet (then . elses) rest
        `(fn-if ,first (fn () ,then) (fn () (if ,@elses)))
        first)))
These implementations are just for demonstration, since they depend on 'if themselves.

-----

1 point by Pauan 5129 days ago | link

Huh, interesting. I think I'll implement it as a fexpr, though, both for consistency (with the other special forms) and simplicity.

-----

1 point by rocketnia 5129 days ago | link

Oops, no time to comment right now, but I figure I'll mention that I just finished ninja-editing that comment to put in links to PicoLisp and Eight.

-----

1 point by Pauan 5129 days ago | link

"Eight's another fexpr language with lexical scope. Like Kernel, it isn't quite complete, but at least it's developed in the open on GitHub. (Hi diiq!) There's a very old topic on Eight here: http://arclanguage.org/item?id=10719 "

Okay, that's a very cool idea: using ' to mean "don't evaluate the argument" (http://arclanguage.org/item?id=10745):

  (def foo ('a b) (list a b))

  (foo (+ 1 2) (+ 1 2)) -> ((+ 1 2) 3)
Of course, actually trying to implement that in PyArc sounds tricky, but that's okay. I can always add it later.

-----