allchars reads all of the characters from a stream, returning a string of those characters. E.g.,
(w/infile file "foo.txt"
(allchars file))
gives you the contents of the file "foo.txt". The above example is the actual definition of filechars: (filechars file-name) gives you the contents of the file file-name.
atend
Tests if an index i is at the end of a sequence s (or beyond the end, technically; the definition is literally (> i (- (len s) 2))). Stupid example:
(let seq '(a b c)
(forlen i seq
(prn (seq i))
(when (atend i seq)
(prn "done!"))))
prints
a
b
c
done!
nil
You can see not-stupid examples in app.arc.
cache
defcache
defcache is like def, except the function defined is wrapped in cache. E.g.,
(= x 0)
(defcache foo 60
(++ x))
defines a function of 0 arguments, foo, which increments x. But the result is cached for 60 seconds -- it doesn't execute the body again until you call foo after the cache has expired. So,
arc> (foo)
1
arc> (foo) ; immediately after
1
arc> (foo) ; 60+ seconds later
2
and so on.
savers*
fromdisk
todisk
disktable
diskvar
The global variable is an implementation detail of fromdisk; it's a hash table of variable names to saving functions ("savers").
(fromdisk var file init load save) creates the variable var if it's not already bound; its value is stored on disk in the file file (if the file doesn't exist, var defaults to init); its value is read from the file via the load function; and its value is stored to the file via the save function.
When we want foo's value, we (readfile1 "some-file.txt"). If the file doesn't exist, foo is set to nil. When we store foo back to disk (using todisk), it's like doing (writefile foo "some-file.txt").
The saver functions are triggered by todisk. (todisk var) writes var to the disk using its saver function. (todisk var expr) updates var to the result of expr before using its saver function. E.g.,
If the sequence is empty, it returns 0 (so there's no chance of a divide-by-zero error).
togglemem
(togglemem x place (o test)) is like a destructive version of
(if (mem x place)
(rem x place)
(adjoin x place test))
For example,
arc> (= xs '(a b c))
(a b c)
arc> (togglemem 'b xs)
(a c)
arc> xs
(a c)
arc> (togglemem 'b xs)
(b a c)
arc> xs
(b a c)
writefile
(writefile val file) writes the value val to the file file. Note that val is not appended; if file exists, it's overwritten.
Phew! Documentation is a lot of work, and I didn't even do that much. :)
Not to belittle the value of documentation (you've certainly done a good job!), but the neat thing about all of these is that I didn't need to look up the prose: their definitions in arc.arc really are that simple. If you're ever stuck or confused about how something works, I encourage you to try looking at its source code. I mean, it's pretty easy to tell what ratio does by reading
(def ratio (test xs)
(if (empty xs)
0
(/ (count test xs) (len xs))))
An English description reads almost exactly like the source code. But I hope my English descriptions are of some help to your project anyways.
I didn't find it at all easy to learn what I wanted from the source code. I mean, imagine I'm sitting here trying to write my first program in Arc. I know I need a loop, say, but which one? I don't even know the names yet. So I search backwards and forwards through arc.arc (or was this one in ac.scm, I can't remember!), finding first one variety then another. And interpreting the meaning of the source when I'm still learning is slow going. Perhaps you've forgotten :-)
Searching the forum wasn't much better. Imagine searching for "cache". Short words are handy to type, but don't yield useful search terms.
So I decided to write things down where I could print them out in a single command, yielding a relatively compact description, and look them up conveniently.
I can definitely imagine better documentation easing the learning curve for new Arc programmers. Source code can be self-explanatory, but only after you've attained a certain base level of fluency with the language. Just as the axioms have to be defined in Racket [1] before Arc can work, they have to be defined in your head before it can make any sense. So I applaud your effort.
One resource that really helped me learn faster was rntz's help system, available in Anarki [2]. It's very convenient because it gives you access to documentation right at the repl:
arc> help.acons
[fn] (acons x)
Determines if `x' is a `cons' cell or list.
Unlike 'alist, this function will return nil if given an empty list
See also [[atom]] [[alist]] [[dotted]] [[isa]] [[cons]] [[list]]
nil
arc> help.alist
[fn] (alist x)
Return true if argument is a possibly empty list
Unlike 'acons, this function returns t when given an empty list
See also [[atom]] [[acons]] [[dotted]] [[isa]] [[cons]] [[list]]
nil
arc> help.afn
[mac] (afn parms . body)
Creates a function which calls itself with the name `self'.
See also [[fn]] [[rfn]] [[aif]] [[awhen]] [[aand]]
nil
Source code can be self-explanatory, but only after you've attained a certain base level of fluency with the language. Just as the axioms have to be defined in Racket before Arc can work, they have to be defined in your head before it can make any sense. So I applaud your effort.
Well put. My thoughts exactly. The suggestion wasn't necessarily to learn Arc by spending a couple days reading the source. I mean, that's what I did, but I was already familiar with Common Lisp. Just that once you reach a certain point (as Preston seems to have), it's not so daunting to say "hey, I wonder what filechars does?" and go read
(def filechars (name)
(w/infile s name (allchars s)))
The ambiguities of certain names in Arc really used to confuse me. acons is the cons predicate and alist the list predicate, but afn isn't the function predicate. Moreover, alist has nothing to do with alists (association lists).
Now that I have better command over the language, these things don't bother me so much. They have their own sense, and I increasingly appreciate how "externally exposed names [are] approximately hamming encoded." [1]
I don't mind short names. Indeed, one of my hopes in learning Arc is to get out from under the sheer bulk of the code I usually have to write to implement my ideas.
Really useful stuff for beginners like me. On a side node, I think examples would be useful in addition to the definition. (This is usually how I learn.. I watch the examples and I only read definition if I don't understand.)
Also, I think we really need a standard module system..