Problems occur if two extensions conflict -- i.e.: if the tests for two different extensions both return true on an input. However, this can easily be modified to create some sort of alert if that's the case.
Problems can also occur if one person's code only works with a certain extension not in place. A solution would probably involve some sort of scoping mechanism like
Having the tests for two extensions return true for an input can be useful, for example if you have a specific case and a general case. By loading the specific extension after the general extension, the specific one will override the general one.
Only problem is if your library is more than just a few files (e.g.: Ruby's RMagick requires you separately install ImageMagick; any Arc bindings to ImageMagick would require similar). Still, this is absolutely great! It seems so obvious and easy I'm surprised no other languages (that I know of) have it.
and the browser doesn't need to download it again if it is already in the browser's cache. This was one of my inspirations as I've been doing a lot of browser Javascript lately. The addition I made was to avoid getting the latest version automatically, as I imagined people might be nervous about that. (I know I would be. After all, Javascript in the browser runs in a sandbox, but Arc on your server can call (system "rm -rf /") etc...)
Things like w/open-file, w/stdout, w/uniq, even perhaps aif and friends, I'd classify as "around code" rather than "resource management."The basic principle behind these is that we do some initialization (e.g.: opening a file), run some code, and then do some terminal work (e.g.: closing a file).
Ruby does similar things with blocks (c.f.: File#open), and I beleive Python has a specfic structure for this kind of thing.
Good point. "Around" is a concept used a lot in aspect-oriented programming. But I suspect that even fewer people are familiar with AOP or "around" than with macros or resource management.
Let's call these anonymous functions whose arguments are the unbound symbols within them in alphabetical order "ofn"'s.
The clearest way to implement ofns is to have a function on the outside of every block of code which does a tree-traversal, collecting all the symbols bound, and then, whenever it finds and ofn, just simply does (sort < (rem [mem _ bound-list] (get-list-of-symbols-used ofn-code)) to find the args list.
There are two major issues with this. The first is global variables -- it needs to determine which symbols will be bound in the global scope at runtime at compile time. Let's assume all global bindings will be done at the top layer or in a layer separated by nothing by calls to 'fn from the top (please, tell me you don't bind your globals in 'eval). (E.g.: (let a 1 (def b ...)) becomes ((fn (a) (= b (fn ...))) 1) and thus meets that criteria, but (def a (b) (= b 1)) becomes roughly (= a (fn (b) (= b 1))), and thus the call to (= b 1) has a call to = between it and the top, and thus will not be counted.) In a process very similar to the overall version, we can then go through the macro-expanded files, and find all the symbols bound by those = forms.
The second problem is nested ofn's (e.g.: [map [map [+ a b] c] d]). I'm still in search of a good solution. I've thought about finding the arity of each ofn (made impossible in the general case by higher-order functions like map which call functions with a variable amount of arguments); finding where each variable is used to determine its minimum scope, and having each symbol an argument of the ofn with that minimal scope; letting inner ofns each have one arg, determined by some alphabetical ordering, and letting the outer ofn have the rest. All those solutions fail some major elegance tests. Best way is probably to just ban nested ofns.
At first I would have said ofn's would be a great feature, but, if we can't have them nested, I can't be so sure -- it would be inelegant to have nested bracketed functions work differently that the outer one, or to have a different delimeter for ofns and normal square-bracketed functions.
Ironically, the difficulty in implementing this dynamic feature stems from the source code of dynamic languages being difficult to analyze.
It seems to me that, however we do it, it would probably be slow. Maybe, as the source is being read in, the compiler/interpreter could somehow flag each symbol as bound or unbound? Then you could have your ofns just inspect all of the symbols below them, and check whether they're bound or not.
About nested ofns, how would you expect them to work? That should be the real test of what method to use in determining which ofns bind which vars. Obviously they're bound in alphabetical order. How about having the outer ofn bind as many vars as it has args, and leaving the rest unbound for the next layer? This would make it impossible to tell which ofn would bind which var at compile time (unless you know the arity of the outer function based on it's environment), but it would (I think) make the most sense. It does leave room for confusing circumstances though ;)
What would happen if there weren't enough arguments to fill in all of the vars? Return a fn? Even more fun!
If the ofns bind inwards, you would need to do your example backwards: [map [map (+ d c) b] a]
You could however try and bind outwards, so the inner ofn binds first, but I don't see how that would be a good idea.
What do you think? Any better ideas? Any glaring flaws with my idea? (I don't know lisp or arc that well)
Source-code traversals are O(n), and compile-speed is not that important below a certain point. And finding all the globals only needs to be done once.
At first I thought it was important to have this conventionalize-ofns function run inside every def and every mac, so that, if I wished to use ofns inside a macro-expansion, which symbols are arguments would not depend on the context. I then realized this would break for virtually any method of generating macro-expansions other than quasiquote, and that, since, under the curretn implementation, two pseudo-gensyms have the same alphabetical ordering as the order they were created in unless they're of different length, it would still be workable (just do a (w/uniq (a b c) ...) and I'll hardly notice the difference -- saves fewer characters overall, but I find it a little more readable; plus, these can be reused if the macro-expansion contains multiple ofns).
If we are to do ofns at runtime, they would be much more workable, but also more unpredictable. I've said once before that a runtime-list of all bound symbols would be desirable for other reasons, but, if I'm testing code in the REPL and set a to some value, I don't want half the functions I call breaking for some mysterious reason. Especially considering I haven't found a way to unbind variables.
Well, I think that the ofns should probably be closures, at which point the binding of the variables only matters when they are defined, after that defining a out of context wouldn't overwrite the a in the ofn. If not, we could have the ofn replace each symbol with a gensym tagged with 1st, 2nd, 3rd, etc. Then it wouldn't matter what you did with the original name. The gensym replacement only happens, of course, if the var is unbound during definition.
Here's a question: how does anarki's [ _1 _2 _3 ] form work when nested?
; convert a cycle into transpositions
(def trans (cycle (o first nil))
(if (no cycle) nil
(~cdr cycle) (list:list cycle.0 first)
(cons (list cycle.0 cycle.1)
(trans (cdr cycle)
(if first first cycle.0)))))
; permute a list using a list of disjoint cycles
(def permute (cycles l)
(with (ts (apply join (map trans cycles))
ret (copy l))
(map [= (ret (- _.1 1)) (l (- _.0 1))] ts)
ret))
(permute '((1 2 3) (4 5)) '(a b c d e))
=> (c a b e d)
An easy way to get an overview of what libraries are available. The Anarki libraries are spread over half a dozen different folders, and for a few of them I don't know what they're meant for even after I read the source code. There needs to be something akin to "gem list".
Nice idea. It would be really great if we had a central website where to put packaged library, so we could query that. I'll try to develop an Anarki-local version.
I've put something on Anarki. You can query installed packages (i.e. packages in the search path) using regular expressions:
> (pack-query "a regular expression")
The query looks in the packages' name and description. The first time it also builds a cache of installed packages name/description in ~/.arc/cache . After installing new packages, use
> (pack-build-cache)
to update the cache. If you try it now on Anarki you'll get no result because there are no packages on Anarki.
How long would 'pack-build-cache have to run? Is it possible for it to just check for newer packages? Because if it's not too long, it might be useful to have it start automatically, or even as a:
(thread
(while t
(pack-build-cache)
(sleep 1000)))
It just dumps the title and the description to a text file and there is no way to check only for newer packages. Maybe it would be possible with a real implementation, this is just a prototype. Making it run continously in the background is thus unacceptable. I don't think it's a problem for the user to type (pack-build-cache) after installing new libraries.
A possible implementation: use the Anarki repository as the website and build the package manager on top of git. I don't know much about gems so I don't know if this would work, but it would save a lot of reinventing the wheel.
To knock down my own suggestion: git isn't suitable for this because it doesn't have any way of partially downloading a repository. At least, none that I can find.