Arc Forumnew | comments | leaders | submit | Darmani's commentslogin
2 points by Darmani 5102 days ago | link | parent | on: Merge let and with into one?

  (mac let/with body
    (if (isa (car body) 'cons)
        `(with ,@body)
        `(let ,@body)))
I'm not that keen on having the same simple macro use different syntax, though.


2 points by Darmani 5112 days ago | link | parent | on: Extend Arc functions

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

  (using-extensions (+ '(table complex)  my-standard-extensions*)
    (my-code [+ ...])


1 point by CatDancer 5112 days ago | link

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.


3 points by CatDancer 5112 days ago | link

Browser-side Javascript is like this in a way, for example to include the JQuery library all you need to say is

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...)


3 points by Darmani 5117 days ago | link | parent | on: Macro Patterns

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.


1 point by jonnytran 5114 days ago | link

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.


3 points by Darmani 5144 days ago | link | parent | on: This would make my programs shorter.

Luckily, Lisp makes this a library-level problem. PG has already made a huge step in the right direction by renaming 'make-hash-table to 'table.


8 points by skenney26 5144 days ago | link

Why not just 'hash? Using 'hash would also help to distinguish hash-tables from html-tables in html.arc


4 points by cchooper 5144 days ago | link

This bugs me too. Perhaps the rationale is that a hash table is not the same thing as a hash (key).


2 points by Darmani 5190 days ago | link | parent | on: Brainstorm: syntax sugar for lambdas

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.


2 points by shader 5190 days ago | link

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)


1 point by Darmani 5190 days ago | link

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.


1 point by shader 5190 days ago | link

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?


May give you a few ideas:


1 point by cchooper 5203 days ago | link

Ah yes, cycle notation!

  ; 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)

  (permute '((1 2 3) (4 5)) '(a b c d e))
  => (c a b e d)


2 points by shader 5202 days ago | link

hmm. I think that cycle notation is sometimes shorter than just stating the final positions, but only rarely.

How about a function that does:

  >(reorder '(2 5 4 1 3) '(a b c d e))
  '(b e d a c)
That makes more sense in many cases. But having a function that does permutations using cycle notation is probably also useful.


5 points by Darmani 5205 days ago | link | parent | on: Where are we going?

Ironically, before that comment, I had been concerned on how this forum had been dead for 6 days...


4 points by Darmani 5244 days ago | link | parent | on: Looking for advice

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".


1 point by stefano 5244 days ago | link

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.


1 point by stefano 5243 days ago | link

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.


1 point by almkglor 5243 days ago | link

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:

    (while t
      (sleep 1000)))


1 point by stefano 5242 days ago | link

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.


1 point by cchooper 5244 days ago | link

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.


1 point by cchooper 5243 days ago | link

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.


We actually already have destructuring, at least for function calls.

  arc>(let (a b) '(1 2)
        (prn a)
        (prn b))