Arc Forumnew | comments | leaders | submitlogin
More documentation (
6 points by prestonbriggs 2624 days ago | 8 comments

4 points by fallintothis 2624 days ago | link

To fill in the blanks of your not sures:

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.

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!"))))

You can see not-stupid examples in app.arc.

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)
  arc> (foo) ; immediately after
  arc> (foo) ; 60+ seconds later
and so on.

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.

For instance,

  (diskvar foo "some-file.txt")
is a macro that expands into

  (fromdisk foo "some-file.txt" nil readfile1 writefile)
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").

Similarly, disktable is defined thus:

  (mac disktable (var file)
    `(fromdisk ,var ,file (table) load-table save-table))
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.,

  arc> (system "ls | grep foo")
  arc> (diskvar foo "foo")
  arc> (system "ls | grep foo")
  arc> (= foo 8675309)
  arc> (todisk foo)
  arc> (system "ls | grep foo")
  arc> (do (system "cat foo") (prn))
  arc> (todisk foo (+ foo 1))
  arc> (do (system "cat foo") (prn))
This way, we can have persistent on-disk variables.

This is a backwards for.

  arc> (do (down i 5 1 (prn i))
           (prn "blast-off!"))

(out expr) evaluates expr, captures the output, and prints it. E.g.,

  arc> (= x 5)
  arc> (out (++ x))
  arc> x
  arc> (out (prn "hi there!"))
  hi there!
  "hi there!\n"
It was defined for news.arc in the function votelink:

  (out (gentag img src up-url* border 0 vspace 3 hspace 2))
If this didn't use out, the gentag macro would expand into

  (do (pr "<img")
      (aif up-url*
           (pr " src=\"" it #\"))
      (pr " border=0")
      (pr " vspace=3")
      (pr " hspace=2")
      (pr ">"))
thus evaluating up-url each time votelink is called. But out evaluates the macro expansion once, turning it into

  (pr "<img src=\"grayarrow.gif\" border=0 vspace=3 hspace=2>")
at compile-time. It's a bit of a fringe use.

Returns a random key of a hash-table.

  arc> (obj a 1 b 2 c 3)
  #hash((b . 2) (c . 3) (a . 1))
  arc> (rand-key that)

(ratio test xs) gives the ratio of elements of xs that satisfy test. E.g.,

  arc> (ratio even '(1 2 3 4 5))
  arc> (ratio odd '(1 2 3 4 5))
If the sequence is empty, it returns 0 (so there's no chance of a divide-by-zero error).

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


3 points by prestonbriggs 2624 days ago | link

Thanks for all of the clarifications.

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.



2 points by evanrmurphy 2623 days ago | link

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]] 
  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]] 
  arc> help.afn
  [mac] (afn parms . body)
   Creates a function which calls itself with the name `self'.
      See also [[fn]] [[rfn]] [[aif]] [[awhen]] [[aand]] 
Had you known about this already?

[1] Or Java (,, or JavaScript (, or Arc itself ( ^_^ I think someone did a port to Common Lisp not too long ago as well, but I can't find the link.



2 points by fallintothis 2622 days ago | link

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


1 point by prestonbriggs 2623 days ago | link

I didn't know of it. Sounds great. Plus, I should be able to write a little program to grovel through his system and gen up a TeX document like mine.

Thanks for the pointer, Preston


1 point by evanrmurphy 2624 days ago | link

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]



1 point by prestonbriggs 2623 days ago | link

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.



2 points by d0m 2622 days ago | link

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