Branches are useful for developing libraries and for following along library development. It was a pain trying to pull in different libraries from different repositories by referencing them by branch name, at least the way I was doing it.
I've already pushed arc3.tar to anarki's "official" branch and merged the changes into "stable". Merging them into the master branch may prove more difficult and tedious, but I think it can be done.
Hmm, as an interim step you could make a macro called "set" which you loaded after Arc and before Anarki. That way you could try out Anarki with arc3 and get things working before going on to do all the tedious renaming.
The trouble is, I wouldn't know where to start with testing anarki as a whole. There's just too many different parts, because anarki has so many things:
- Forks and compilers (arc2c, arc-f)
- Pet projects and examples (LightMakesRight, wiki-arc)
- Extensions to arc (help strings, function signatures, compilation)
- Bugfixes to arc (making 'atomic work even on exception throw)
I think I can probably update the latter three, but the former will just have to rely on whoever contributed them. Perhaps it's time for a new anarki - throw out the unmaintained cruft and try and separate changes to core arc functionality (bugfixes, extensions) from additions/libraries from standalone projects.
From my cursory look, pg has fixed many if not most of the core issues that anarki resolved. (ie cut fn not handling -1, providing a static directory for files to be published, added some basic math functions - sin cos etc..).
I would suggest starting a new branch with arc3 and if the libraries from anarki are still relevant then people will incrementally add them. This way were not integrating a bunch of code just because it's there - even though it's no longer useful.
+ just because you make them work with core arc3 files doesn't mean there will not be conflicts - as example the int function in the anarki math.arc library conflicts with news.arc only (as pg added an int function).
Some of the things anarki adds that are not in arc3 are tremendously useful.
For example, help strings and the 'help macro to access them, and similarly, the ability to call up any function or macro's source with 'src.
I do think the idea of integrating anarki code incrementally is probably the right way to do it. To this end, I've forked anarki's "official" branch (http://github.com/rntz/arc), and I've been applying CatDancer's "minimum-distance-from-arc" patching philosophy (http://catdancer.github.com/sharing-hacks.html). We'll see how many things from anarki I end up converting this way.
When you're done with you're patching process (I wouldn't mind helping) we should probably merge it back into nex3's copy, as his has public commit access.
One approach is to only port over things that you personally use and care about; and let other people port over things they care about. That's a pretty good filter for separating out the important from the unimportant.
Just giving it a preliminary look over, it seems like you changed 'set to 'assign. Any reason for this in particular, pg? It seems like it changes a lot of code, and as 'set is fairly common, it kind of goes against the philosophy of short names for common operators.
It's not so many uses that it's impossible to update. Many if not most of these uses could admittedly be replaced with '=, and arguably this was the correct thing to do in the first place. It just seems like an odd decision, and I'm wondering if there's any specific reason for it.
In my opinion "set" is a better name for what "assert" used to do, and I think "set" was available since it was being used for a low-level operation for which in user code "=" is a better and shorter name.
"I worry about releasing it, because I don't want there to be forces pushing the language to stop changing. Once you release something and people start to build stuff on top of it, you start to feel you shouldn't change things. So we're giving notice in advance that we're going to keep acting as if we were the only users. We'll change stuff without thinking about what it might break, and we won't even keep track of the changes."
As far as I know, windows is not officially supported. I think I've gotten it to work on windows before, but you might have some trouble with file system differences, etc.
However, the place to type that in is a command line window in the folder arc was unzipped to.
So for example:
1) Type Windows Key-R to bring up run window
2) Type in "cmd", and hit enter to bring up command prompt
3) Use the "cd" command followed by the directory path of your arc installation.
4) Execute "mzscheme -m -f as.scm" to start arc.
Alternatively, if you're using Vista (not sure about XP), you can Shift-Right Click in a explorer window, and click the dropdown item "Open Command Window Here" to do the same thing as the first three steps.
Thank you for your help. I tried to follow these directions, but it didn't work. I'm not sure I understand them correctly. Steps 1 and 2 are fine, but maybe I didn't do step 3 or 4 the right way. Here's what happened:
I have a folder with MzScheme in it and a folder with arc3 in it. I entered "cd" and the directory of the arc3 folder: "cd C:\Program Files\Arc\arc3" and then I hit enter. The next line looked like this:
C:\Program Files\Arc\arc3>
so I typed in "mzscheme -m -f as.scm" and pressed enter.
This message appeared: 'mzscheme' is not recognized as an internal or external command, operable program, or batch file.
Do I need to be more specific with my directory path? Is there a file inside the arc3 folder that I need to name? Or am I not executing "mzscheme -m -f as.scm" when I type it in?
Ok, so the problem is that windows doesn't know where to find mzscheme.
To rectify the situation, you could either type in the full path to mzscheme instead of just it's name, or you could add it to your PATH variable (that's where windows looks to locate programs when you type them in on the command line)
Here's how to do that temporarily:
PATH=%PATH%;<insert mzscheme path here>
Again, that's PATH=%PATH%, followed by a semicolon and then the path to mzscheme. Unfortunately, this is a temporary fix that will only last as long as that command window.
To make it permanent: right click on "Computer" and go to properties. Somewhere there should be an Advanced Settings link, which should pop up a new window. Click the Environment Variables button, and edit the PATH variable (either for your user or the whole system). Add a semicolon, and then paste in the path to the mzscheme executable.
I've got a news forum running, but it's on a very small box so I don't know if I want to drive much traffic to it ;)
At any rate, I'm interested in getting an FCGI interface for arc so that I can host it on Dreamhost. They don't support scgi or a network daemon, so I can't use mod_proxy. If anyone is interested in helping, let me know ;)
There was one attempt a while ago to get mysql to work with arc.
As for using arc as an cgi script, it has a rather slow load time. If you are loading for every request it will be quite slow. That's one reason that arc includes it's own web server.
One common way of using arc is to run it behind an apache server with mod_proxy.
[ I guess opening a socket to the db server and parsing the resultset wouldn't be much harder if its text mode - could probably use the perl or ruby pglib as a guide, and port from that... ]
Hmm. I would think that you wouldn't want to open a new psql connection every time you want to look something up.
How about running the system command in a thread, which redirects psql's stdin and stdout to named pipes so that another arc thread could read from it using file read commands? That would give you more persistence, so you wouldn't have to keep loading psql.
Also, have a look at lib/mysql-ffi.arc in anarki; supposedly it has a ffi for mysql, though I haven't really looked at it much myself.
I found a bug, surprise surprise. Apparently it doesn't seem to count things bound before it in a withs as bound. I presume it is because the nested lets are not actually executed before the bound function is called in the macro expansion. Any ideas on how to get around that? This sounds like a good place for run-time macros ;) That, or a method of having code be more aware of its context; i.e. having the macro-expansion look to see if it was called inside of a form that would bind something (mainly fn). That sounds even harder.
So, apparently it works ok when called directly from the repl, but due to the compile time nature of macros it has trouble with being built into functions or called in other macros.
What does all of the auxiliary code for make-br-fn do? (all of the *mbr functions) They probably don't have much to do with this, but it seems like an awful lot of code just to implement make-br-fn.
The auxiliary code is responsible for finding all the variables in the code and then finding all the _\d+s (and __) that occur free in the expression. It's probably bulkier than it needs to be---I wrote it with a decent amount of class experience in writing interpreters, but without any real-world experience. The big thing you seem to be missing is expand, which will macro-expand its argument. That would result in the following change:
I've looked at expand; how does it help there? Is that necessary to expand macros inside a bracket function?
I still have no idea how to check binding at compile time; in theory it could know that it was inside a binding expression (fn) but I think that would take a lot of modification to the language, and probably isn't worth it, unless it allows other nifty features.
Aha, I see. Yes, in this case, expand probably won't help. But it's actually conceptually simple to checking binding (without eval) at compile time; that's what make-br-fns does, after all. What you do is you run expand on the source tree, then just go through and check and see if it's within a fn. This is what all the auxiliary functions for make-br-fns are doing: checking to see what's in an argument list, seeing if variables used are in argument lists, etc. Obviously this breaks if you run, say, (eval '_2), but it works in other situations.
Wait, how does it know what context it's run in? I can see checking if the symbol is bound underneath it, but what about checking to see if it is bound above? (i.e. br-fn inside a withs) How does that work?
...Oh dear :-[ It doesn't, and I hadn't noticed that until right now. Apparently, it's not a problem, presumably because nobody ever declares variables called _1 :P Yeah, I don't see a feasible way to do that, unless make-br-fns produces something like
Even the 'eval thing wouldn't work. 'eval evaluates its argument at top-level, so the function would no longer be lexically scoped within its environment. You wouldn't be able to write anonymous closures anymore, just anonymous toplevel functions. Moreover, 'bound checks whether its argument is bound at global scope.
Unless there was a way for a function to examine its declaration environment. Then we could have a function that crawls up the tree looking for binding statements, and removing those from the list of unbound symbols. I just don't know how hard that would be to add. It could be useful for other things though, like better error messages. If the context were mutable, it could allow macros to do a) really cool things and b) likely very buggy things. But if people knew to expect it, it might be ok.
How would you implement a read-only context, visible during compile time? Is it even possible? In theory, the reader has already read in the other stuff, and parsed it into a list.
Allowing a macro to know what lexical variables are bound in its calling environment is perfectly possible, though it would require some modification to ac.scm. In order to translate arc symbols into mzscheme symbols, the compiler already keeps track of what variables are locally bound. So you'd need to modify the compiler so that this list gets passed in as a "hidden parameter" to macros, and make a special form to access it. However, I'd advise against implementing this, because there's an even more unsolvable problem. Even if you fixed it, the following would still break:
The intended meaning of [square x] here is (fn () (square x)). But because 'square is not bound at the time of [square x]'s macroexpansion, even if you did have the more "intelligent" version of 'make-br-fn, it would end up as (fn (square) (square x)). At present, of course, it ends up as (fn (square x) (square x)).
Hmmm. So how about looking for only unbound single letter symbols? That would cut out all of the predefined functions, and still provide usability (I wasn't going to use it with anything more than x y z and a b c anyway.
If not, I guess there's no point in continuing to pursue this idea, is there ;)
Maybe we could look at only single letter symbols, or symbols that start with _. That would give compatibility with (most) of the current uses; the only times that it wouldn't work would be when it was used in a function that had a single letter parameter. So, maybe I should just give up then ;) Even though I don't really like _1 _2, etc., I guess it's the most viable option.
> Are you thinking of a shortcut to macex, to expand expressions at runtime?
I guess so. I don't really know what I'm thinking, to be honest. I think that anon. macros would be useful in cases where you want a little bit of syntax modification, but not make a whole macro out of a function.
For instance, I have found it difficult to make a set of functions taking rest parms built on top of a base function that also takes rest parm. In order not to get the extra layer of cons around it, I end up having to make a macro for calling that base function, to splice the arguments into the list. Maybe I'm doing it wrong, and there's a better way, but it seems like it might be an application for a short anon. macro.
That's not the case; apply doesn't care how many arguments the function takes. Take map (which takes a mandatory argument and a rest parameter) and map1 (which takes two mandatory arguments):
arc> (help map)
(from "arc.arc")
[fn] (map f . seqs)
Applies the elements of the sequences to the given function.
Returns a sequence containing the results of the function.
See also [[each]] [[mapeach]] [[map1]] [[mappend]] [[andmap]]
[[ormap]] [[reduce]]
arc> (map list '(1 2 3) '(4 5 6))
((1 4) (2 5) (3 6))
arc> (apply map list '((1 2 3) (4 5 6)))
((1 4) (2 5) (3 6))
arc> (apply map (list list '(1 2 3) '(4 5 6)))
((1 4) (2 5) (3 6))
arc> (help map1)
(from "arc.arc")
[fn] (map1 f xs)
Return a sequence with function f applied to every element in sequence xs.
See also [[map]] [[each]] [[mappend]] [[andmap]] [[ormap]]
arc> (map1 [* 2 _] '(1 2 3))
(2 4 6)
arc> (apply map1 (list [* 2 _] '(1 2 3)))
(2 4 6)
As long as the last argument to apply is a list, you're golden.
Interesting. I was wondering if that might be the case.
So I guess that we don't need an anon. macro for that ;)
I'm also wondering whether we would ever actually want an anonymous macro, since often they turn out to be so general purpose that you might want to make a utility out of it.
I'm not really clear on what an anonymous macro would do. Transform code? If we're writing it in one place, we can just transform it right there. Can you give a usage example?
And no, Arc only has ordinary macros and ssyntax. Though actually---and this just occurred to me now---you can use ssyntax to create symbol macros. For instance, I have the following in a library file
The first two let me write (@func arg1 restargs) instead of (apply func arg1 restargs) and ($func xs) instead of (map xs). However, this $ makes the $ macro misbehave, and so I added ssyntax turning @ into apply and $ into the original $ macro. It turns out that this technique is fully generic, since ssyntax essentially does a find-and-replace on symbols:
arc> (= defsym add-ssyntax-top)
#3(tagged mac #<procedure>)
arc> (defsym RANDOM (rand))
t
arc> RANDOM
0.5548165450808223
arc> RANDOM
0.15745063842035198
arc> (= things '(alpha beta gamma))
(alpha beta gamma)
arc> (defsym THING1 (car things))
t
arc> THING1
alpha
arc> (= THING1 'one)
one
arc> things
(one beta gamma)
arc> (defsym NOISY (do (prn 'HI) nil))
t
arc> NOISY
HI
nil
arc> (car NOISY)
HI
nil
This is actually really nifty, even if it's an unintended side effect. On some level, though, I'm not fully convinced of the value of this---it seems a bit omnipresent. Then again, Common Lisp works fine with them, so perhaps they're fine for Arc too. Are there naming conventions for symbol macros in Common Lisp? I used capital letters above just because I wanted some distinguishing mark.
There are a couple of caveats: first, every time you run add-ssyntax-top, you'll add another entry to the ssyntax table instead of overwriting the old one, so redefinition will make ssyntax slower if it's done too much. Second, the five tokens R, r, L, l, and ... are all unavailable, even if quoted; they turn the given string into modifying ssyntax, not standalone ssyntax. Still, this is a new option I hadn't thought about yet.
What do you suggest we do about all of the foundation functions? Most are defined in scheme using xdef, some using set (def and mac). I could add hooks to those (especially xdef) but I don't know how well that would work.
Hard coding it probably isn't a good idea; the source would get out of date, and be hard to maintain. Besides, it violates the DRY principle.
1) def and mac now add entries to a table named source*
2) there are now two macs fro accessing those entries: lsrc and src. lsrc returns the source as a list, so that you can modify it, etc. src pretty-prints lsrc, so that you can read it better from the repl.
3) I also changed fns so that it a) takes both arguments as optional and b) will accept symbols as arguments. Here's a few examples on how to use fns:
arc> (fns)
*returns the signatures of all macros and functions currently defined*
arc> (fns f)
*returns the signagures of all functions and macros beginning with f*
arc> (fns nil [fancy-filter _ ])
*returns the sigs of all fns and macs which pass fancy-filter.*
In the last form, the br-fn cannot reference the first argument.
It could possibly be modified so that it tests if the single argument is a function or a symbol, and if it is a function it treats it as the filter, otherwise it uses prefix with the string of the symbol.