cchooper


17 points by cchooper about 1 year ago | link | top
cached 12 days ago
Personally, I think the only thing that went wrong in the history of Arc is that pg didn't correct people's misunderstandings about what it was, and what it was trying to achieve. A 100-year language is not going to be usable tomorrow, and a language designed by the optimal number of people (one) is not going to accept many patches!

If people want a practical language to use now (and there's nothing wrong with that!) then they should go ahead and build one. I'm happy to join any project that anyone may have for developing an Arc-like language. I might even start one myself (why not? It'll be fun!) if I have the time.

A language doesn't survive in its implementations, but in its ideas. Modern languages (especially Python/Ruby, but even C# and Java) are becoming Lisp. Dynamic typing, late binding, functional programming, closures, generic functions, MOP... the 'popular press' laughed at them, but now these are the hot topics in language design. Those ad hoc, informally-specified, bug-ridden, slow implementations of half of Common Lisp are getting better every year. Common Lisp and Scheme will die, but in 10 years everyone will be using Lisp, and they won't even know it.

The same goes for Arc. Clojure already uses some ideas from Arc (e.g. fewer parens in conditionals). If the ideas are good (and I think they are) then they'll spread. If people want to build new languages (e.g. Arc3F) that use them, then that spreads them further, That, I think, is the true future of Arc, as a source of eternal ideas.


15 points by cchooper over 2 years ago | link
cached about 21 hours ago

12 points by cchooper over 2 years ago | link | top
cached 11 days ago
Aha! I think I've got it. Here's my explanation of what it's doing (I had to write all this just to work it out!)

First, the value of (catch throw) is stored in k. The catch function does this: get the current continuation and bind it locally to the symbol throw. So we get the current continuation, bind it to throw, and then return throw. So all we've done is return the current continuation at (catch throw).

In the next line, we print 1, so our output looks like this:

  => 1
In the next line, (catch (k throw)), we again get the current continuation and bind it locally to throw. But this time we call the continuation stored in k, passing throw as an argument. This rewinds us back to the beginning, so that the original (catch throw) now returns the value of throw in (catch (k throw)). This value, of course, is the current continuation at the line (catch (k throw)). This new continuation will become the new value of k.

Now you have to remember this about the continuation at (catch (k throw)): although we've rewound the stack back to the beginning and reassigned k, this continuation was created when k had the value it originally had, and it remembers this original value because of lexical scoping.

Anyway, back to the action. We've rewound back to the beginning and stored the continuation at (catch (k throw)) in k. Execution continues at (pr 1), so we get another 1 in our output.

  => 11
Now we get to (catch (k throw)) again. This time, k is the continuation originally created at (catch (k throw)), so we jump back to this line (i.e. the same line), but remember, we've gone 'back in time' (spooky music) to when k had its original value. We continue execution at (pr 2):

  => 112
and then get to the final (catch (k throw). Remember, k now has its original value in this context, so we jump right back to the start again at (catch throw) and give k yet another new value: the continuation at the second (catch (k throw)). Remember, in the context of that continuation, k is still set to its original value! (athough this isn't important because we're not going to use it.)

Now we are at the top, so (pr 1) gets executed again:

  => 1121
Then we get to (catch (k throw)). At the present time, k is bound to the continuation at the second (catch (k throw)), so we now go back in time again to when we were there. The second (catch (k throw)) returns its value (which is lost) and we get on to the next line, (pr 3)

  => 11213
Finally, we have reached the end and return nil, so the final output is:

  => 11213nil

11 points by cchooper over 2 years ago | link | top
cached 5 days ago
It would be really nice just to know what's going on, even if the answer is "Not for a long time because..."

10 points by cchooper over 2 years ago | link
cached about 1 year ago
Arc has some nice primitives for reading and writing text files... so long as those files are Arc code. If you're just manipulating plain text or binary, then your options are rather more limited.

So here are two operators that make it a bit nicer to work with any kind of file or port. First up is drainf, which works just like drain except that you can call any function on the stuff you're reading from a port (drain just dumps it all in a list).

  (mac drainf (expr f (o eof nil))
    (w/uniq (gdone gres)
      `(let ,gdone nil
         (while (no ,gdone)
           (let ,gres ,expr
             (if (is ,gres ,eof)
                 (= ,gdone t)
                 (,f ,gres)))))))
What is drainf useful for? Well, for implementing things like this next function: pump takes two ports and pumps all the data from one port to another.

  (def pump (in out (o binary nil))
    (with (err-flag t
           inport  (if (isa in  'string) (instring  in)  in)
           outport (if (isa out 'string) (outstring out) out))
          (after
           (do
            (if binary
                (drainf (readb inport) [writeb _ outport])
                (drainf (readc inport) [writec _ outport]))
            (= err-flag nil)
             (if (isa out 'string)
                 (inside outport)
                 out))
           (if (isa in  'string) (close inport))
           (if (isa out 'string) (close outport)))))
You can specify character (default) or binary ports. You can also pass strings instead of ports, in which case pump will pump data to/from your string. For example, to write a string out to a text file, do this:

  (w/outfile o "myfile" (pump "Some text" o))
or if you want to read a text file into a string, try this:

  (= text (w/infile i "myfile" (pump i "")))
or you can specify two file ports to copy the contents of one file to another, or two strings to copy the contents of one to another (????) or whatever.

10 points by cchooper about 1 year ago | link
cached 11 days ago

10 points by cchooper over 2 years ago | link
cached 8 days ago

10 points by cchooper over 2 years ago | link
cached 1 day ago

9 points by cchooper over 2 years ago | link | parent | top
cached 14 days ago
In the future, everyone will use Lisp, but they won't know it's Lisp, because it will be called Microsoft Windows Dynamic Service-Oriented Parenthesis Construction Language for .NET.

9 points by cchooper over 2 years ago | link
cached 9 days ago