Nice touch. BTW, Googling for 'install arc lisp' gets the wiki to the top page or close. I'm hoping that eventually we can get just 'install arc' or 'arc lisp' to do the same. Just 'arc' looks like mission impossible. :) Adding more links to the wiki will help. So listen up, all Arc-fu exponents!
The data is stored in flat files under the arc/news subdirectory. So just moving the entire code directory should transplant data as well. All data is stored in memory and periodically saved to that directory (so you'll be fine as long as you don't need to add a second server).
It's in a branch for the old Arc 2, so it probably won't work with Arc 3.1. It should provide a starting point, though; let us know if you get it working, and feel free to push it to http://github.com/nex3/arc/tree/master.
Found via http://lambda-the-ultimate.org/node/4444, an interesting way to replace compiler error messages with a dialogue. It vaguely reminds me of common lisp's restarts.
Arc/Nu is Lite Nu + other features. At the time of this post, those additional features include:
* redef/remac/extend
* defcall
* `var` for accessing global variables (I will probably change the name)
* implicit parameters
* utilities for inspecting/manipulating paths, such as cwd, dirname, basename, etc.
* an `import` macro for easily loading files
There are also some libraries in the lib/ subdirectory, and applications I've written in the app/ subdirectory.
---
Why yet another branch on GitHub? I have three major projects right now:
1. The Nu compiler, which is used for Lite Nu and Arc/Nu. It's intended to be very compatible with Arc 3.1 while fixing bugs and making it possible to add additional features.
2. Arubic, which is my language based loosely on Arc.
3. arc2js which intends to allow you to execute Arc/Arubic code in the browser.
To put it another way, the three projects are essentially: Arc 3.1, Arubic, and JS. Arc/Nu is a part of project #1, but I got tired of implementing Arubic and arc2js, so I decided to add some convenience libraries on top of Lite Nu, which is a lot easier to do.
So now project #1 is split into two separate sub-projects: Lite Nu and Arc/Nu. Lite Nu is for people who just want Arc 3.1, period. No conveniences, no new features. Just Arc 3.1. Arc/Nu is for people who want Arc 3.1, but also want some shiny new features.
"you might also decide to keep apply, but have it only work on functions. Then you'd use eval to "apply" fexprs. After looking at the issue, I'm not really opposed to that."
You know, I was tempted to define all-true as a macro:
mac all-true(xs)
`(and ,@xs)
This way I would get to keep a simple implementation. The price seems too high for my taste, however. Splice can cause macros to spread through a codebase like a virus. Macros are awesome to have, but I want to be careful not to overuse them.
a) Default values are not inlined during initialization. Before:
> (inst 'foo)
#hash((field1 . default))
After:
> (inst 'foo)
(tagged tem (foo #hash() ...))
Non-existent fields are looked up from the template at read time. This is useful if you ever want to change the default. Say you decide to change the default value for showdead in HN. If you updated the template today it would only update for new users. You could go through and set everybody's showdead, but that seems invasive. After my changes existing users will pick up the new default, but if somebody tried setting showdead in the past and explicitly reset it to the default -- then they get to keep their setting.
b) Reading from file now includes all fields rather than just the ones included in the template. Does this seem reasonable? I think the reasoning for dropping unknown fields was so you could upgrade or rollback the template and it would work with existing data. But if you delete a field it doesn't do any harm if it's set, right?
inst has always permitted unknown fields, so this way things seem more consistent.
"Are you saying this should work even if list was a macro/fexpr?"
Yes. But as soon as you try to make it work with fexprs you'll run into the following problem. Here's what I wrote earlier:
"To put it another way, (apply list '((1 2))) would be equivalent to (eval (cons list '((1 2)))) which is equivalent to (eval (list list '(1 2))) which is equivalent to (eval '(list (1 2))) which is equivalent to (list (1 2))."
What I'm saying is that if you changed apply so it worked with fexprs, then (apply list '((1 2))) would be equivalent to (eval '(list (1 2))). If you try evaluating that, you'll get an error saying something like "1 isn't a valid function call" or whatever.
That's because functions evaluate their arguments. So when the "list" function evaluates the argument "(1 2)" it tries to call the "1" function with the argument "2" which obviously fails.
So instead you have to call (eval '(list '(1 2))) to suppress evaluation. Note the extra quote! So what rocketnia said (and I now agree with) is that the "apply" function would have to map quote over each of its arguments. In other words, (apply list '((1 2))) would basically be the same as (eval '(list '(1 2)))
Alternatively, if functions were "wrapped" fexprs, then apply could "unwrap" the function, which would lead to more-or-less the same effect, sans a few details.
In other words, you'd either define "apply" like this...
In fact, the above is the definition Kernel uses[1]. But if you're implementing apply with eval, then you might be better off not implementing apply at all and just using eval directly. In other words, rather than saying (apply foo '(bar qux)) you'd say (eval `(,foo bar qux)) And rather than saying (apply foo bar) you'd say (eval:cons foo bar)
This should work with both fexprs and functions in a (hopefully) intuitive way.
---
Oh, yeah, you might also decide to keep apply, but have it only work on functions. Then you'd use eval to "apply" fexprs. After looking at the issue, I'm not really opposed to that. It seems reasonable, provided that supplying arguments as a list is most common with functions. The lack of consistency does bug me a little, though.
---
* [1]: If Kernel already uses that definition, why does apply supposedly only work with functions? I believe (without actually checking) it's because the unwrap function throws an error if the argument isn't a function. So you can't call unwrap on fexprs.
If I understand correctly, if wart allowed for calling unwrap on fexprs (it would just return the fexpr) then the above definition of apply should work just fine for both functions and fexprs.
"I guess I don't understand everywhere that you're disagreeing."
The only area I currently disagree with rocketnia is this: "Unfortunately, neither of these approaches does what you want with 'def."
---
"For example your analogy for def sounds exactly like what Pauan is saying. What am I missing?"
Yes, it is exactly like what I was saying. The point was that if you changed apply so it worked with def (and other fexprs) it would then break functions like list. Finding a way so that apply can work on both fexprs and functions is one of the points of unwrapping functions.
---
"But that's how it should behave, right? Is that not what Pauan is suggesting as well?"
Absolutely not. It should behave like (list '(1 2)). That is how it would behave if apply unwrapped functions, or if apply mapped quote over the arguments.
Of course, one could make the argument that you should have to say (apply list '('(1 2))) instead... but in that case I'd rather have two separate operators: one that works on fexprs, and one that works on functions.
Or perhaps you could just use eval for fexprs: (eval '(def foo (a b c) (+ a b c))) That seems perfectly reasonable to me as well. But that's equivalent to saying apply should only work on functions. And in that case, why do you need apply at all, since eval works on both fexprs and functions...?
Even though Pauan understood me, I'll reply again in case it helps. ^_^
---
"But why would apply need to map quote on the argument list? If it simply doesn't evaluate the individual sub-expressions, then it should be the same thing."
Since you (Pauan) would have procedures be fexprs that explicitly eval'd their arguments, using apply on a procedure would cause the procedure to eval the args. Whereas (apply list '((1 2))) results in the list ((1 2)) in Arc, in this hypothetical language, 'list itself would try to eval (1 2) and get an error.
In other words, the Scheme/Arc/Kernel 'apply takes a list of argument values, not expressions, so (from a certain point of view) they're not actually suitable arguments for an fexpr call.
If we want Scheme/Arc/Kernel-like behavior, 'apply can make up for the procedure's own evals by quoting the args, or it can make up for them the way it does in Kernel, by unwrapping an applicative into something that skips the eval-my-args step altogether.
Personally, I think unwrapping is cleaner, but quoting makes (apply and foo) behave like (all idfn foo), which is what people seem to expect. Unfortunately, neither of these approaches does what you want with 'def.
---
"It seems to me that (apply def '(foo (a b c) (+ a b c))) should be exactly equivalent to (def foo (a b c) (+ a b c))."
Pauan, the step-by-step way you comprehended my response to this is great, but I wasn't reasoning in that much detail. :-p I was mostly going by analogy:
(apply def '(foo (a b c) (+ a b c)))
(def foo (a b c) (+ a b c))
*** success ***
(apply list '(foo (a b c) (+ a b c)))
(list foo (a b c) (+ a b c))
*** error: unbound variable 'foo ***
(apply list '((1 2)))
(list (1 2))
*** error: can't call 1 ***
(all-true (list '(1 2)))
(apply and '((1 2)))
(and (1 2))
*** error: can't call 1 ***
I don't think that does what you think it does. Suppose 'map is implemented independently of 'apply, and that it takes this form:
(def map (f seq)
...
... (f elem) ...
...)
Then (map quote '(1 2 3)) should result in the list (elem elem elem). That's what my intuition says anyway, not that it's really useful behavior. :-p
Mapping [list quote _], as I was talking about when I called it ($lambda (x) (list $quote x)), will hopefully work regardless of what mapping quote does.
You can make the env argument optional if you like, with whatever semantics you want (the current environment, a new environment, etc.)
---
Side note: why doesn't Arc 3.1 use this definition? Because eval is incredibly slow in Racket, but applying a function is fast. But I'm assuming in a language that emphasizes fexprs (like Kernel, or wart) that eval should be plenty fast.
I didn't at first either. But I walked through the steps one-by-one until I figured it out. Here they are:
apply is a function, so it evaluates all its arguments. When calling (apply list '((1 2))) its arguments evaluate to the function list and the list ((1 2)). It then calls the function list with the argument (1 2). This is equivalent to (list (1 2)), as rocketnia said.
---
To put it another way, (apply list '((1 2))) would be equivalent to (eval (cons list '((1 2)))) which is equivalent to (eval (list list '(1 2))) which is equivalent to (eval '(list (1 2))) which is equivalent to (list (1 2)).
Thus, you would either need to say (apply list '('(1 2))) or apply would need to map quote over the arguments list.
Yeah, I guess that's something we can agree on. No use having a serialization mechanism that thinks the stored version of the value is just a suggestion. :)
Until now, I was thinking this was potentially a positive (albeit an inconsistent positive) since it was a convenience to anyone who wanted to manually edit pickled values, as might happen with a configuration file or something. That doesn't seem nearly as crucial a feature as serialization, and from the looks of your 'temstore utility, it might even still be possible.