> I've had to think about the scheme substrate a lot when I hack on arc; arc feels a very leaky abstraction as a compiler. The hard part in programming is switching layers of abstraction; if an abstraction boundary is leaky enough, just taking it out entirely may make things easier. That's the hypothesis, anyway.
Sounds like an accurate assessment of Arc, though I guess I've been itching for the opposite (probably more obvious) outcome: an entirely platform-independent "arc.arc" with only the handful of axioms in "ac.scm" to bootstrap and guide ports of Arc to other substrates.
Absolutely. One benefit of the transformation layer is that it allows you to grow the language. It could eventually be completely self-sufficient, but you can start with the hard/interesting parts, and other stuff can gradually be abstracted away.
As an example, ac.scm has a comment that ar-gensym is a toy implementation. I don't need to do toy implementations because I can just use PLT's gensym directly until I decide to build my own.
> I'm trying to build a substrate that people can fork off for new languages
I sense a common (albeit very general) theme with Readwarp. :)
> As I go over arc's functions and macros, I see a few things that just macros won't fix: if and cond treat () as false; if, + and map can take any number of args; car and cdr don't barf on (); let needs fewer parens and can handle destructuring more transparently. In these cases I plan to make it easy to just replace if with my-if in the transform phase.
Must be misunderstanding you here. I thought most of these (esp. 'nil and '() both being false, those utilities taking any number of args) were well-publicized features of Arc, not bugs. Were you perhaps referring to PLT's functions, or could you otherwise clarify please?
> I often programmed with my program in a window on one side and arc.arc open in a window next to it.
I love doing this.
Definitely an interesting project. I'm glad you decided to share about it here and sorry for not providing richer feedback on the actual idea in this comment.
> "I thought most of these (esp. 'nil and '() both being false, those utilities taking any number of args) were well-publicized features of Arc, not bugs."
Yeah each of these is absolutely an improvement. I meant that these are the reasons arc needs to be a language with a compiler rather than a macro library. So they're the parts that are challenging to reimplement without building a monolithic cond.
If so, it has taught me something about templates: they're simply tables on writes/saves; it's on reads/loads that their difference manifests (as far as I/O is concerned, anyway). [1]
[1] And the same can be said for tables and alists, since tables get 'tablist-ed before they're written/saved. Neat!
I originally wrote it with 'def but switched to 'mac precisely for that inconvenience. Could do it your way with:
(mac wipeop (op)
`(wipe (srvops* ',op)))
I like that these actually use 'wipe and literally wipe the op. The others are more parallel to 'wipe though in that they make the page say "nil" instead of "Unknown." Recall 'wipe sets a place to nil instead of undefining completely and making it cause
Error: "reference to undefined identifier: _test"
OTOH, I've wished before that 'wipe actually did this, and I realize it's kind of a trivial point.
> It was a lot harder to find than I think it ought to be, but perhaps my google-fu is simply weak.
You're not alone. I lost that page many-a-time before I finally bookmarked it.
Re: your earlier thought, it is technically unofficial documentation. You may find Search Arc Forum [http://af.searchyc.com/] a useful tool for future Arc-related searches. (Although simply searching Google with "site:arclanguage.org <query>" works pretty well.)
I think you're new here... welcome to the forum! :)
I like this idea and think it fits well with Arc's theme of compactness.
What are all the possible implications? For example, it could be implemented as an isolated feature, but having negative indexes start from the right kinda makes me crave a '-car and '-cdr that start from the right as well. Additionally, if you're going to wrap around at the zero index, does it make sense to wrap around at all indices where mod length equals zero? That is, does
(let xs '(a b c)
(and (is xs.0 xs.3)
(is xs.1 xs.4)
(is xs.2 xs.5)) ; etc.
evaluate to true? This would be kind of a serious change and probably not very useful, IMO. (To be sure, I'm not really suggesting that these follow from your idea per se but rather from taking its characteristics to extremes.)
Finally, just a ssyntax question: would
xs.-1
work? I think it certainly should if negative indexing were implemented, just wondering if our underlying machinery might have trouble correctly parsing the dot and hyphen together.
To model indexing after Python, valid indices for a sequence of length n would be integers in the range [-n, n).
>>> xs = ['a', 'b', 'c']
>>> xs[0] is xs[3]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list index out of range
>>> xs[0] is xs[-6]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list index out of range
>>> xs[0] is xs[-3]
True
Hence "To model indexing after Python". I figure Python's probably a good source of inspiration for Python-like features. ;)
Admittedly, I can't find specific rationale for IndexErrors discussed anywhere. Perhaps throwing errors for egregious indices just seems the "sane" thing to do. Essentially, it's a choice of foist: if indexing wraps around infinitely, you need to check bounds when you don't want to wrap around; if indexing throws errors, you need to mod explicitly when you do want to wrap around.
> if indexing wraps around infinitely, you need to check bounds when you don't want to wrap around; if indexing throws errors, you need to mod explicitly when you do want to wrap around.
Good summary. I agree that index-out-of-bound errors are the saner default.
More generally, I'm interested in knowing how you all approach writing JavaScript for your Arc webapps. Do you have a way of embedding it in Arc source, or do you write it independently and take advantage of the myriad tools available for development in JavaScript proper?
I start out just emitting strings, and gradually add structure to repeated patterns using string-emitting functions. And yes, I call this file js.arc. But it's not very comprehensive at all yet.
ArcLite is really neat [http://jonathan.tang.name/files/arclite/], but that's something different: Arc ported to JavaScript and a browser-based REPL. I'm thinking of something more like an "html.arc" for generating Javascript from Arc ("js.arc"?).
If all you have is a .js file that loads separately, yes it makes no sense to write it in s-expressions. But javascript also needs to be dynamically generated, especially in event handlers (onload, onclick).
I want to codegenerate js for the same reason I want to codegenerate html: because it's shorter and easier to read when everything isn't in a single string, and because I can eliminate error-prone string escaping. String escaping is perhaps rjs's biggest benefit.
Hmm, what would be a good example? I've been building utilities for modifying urls with javascript before sending out a request. Here's how readwarp prompts you if it thinks you might not be interested in any more stories from say 'Health':
; Add 'group=Health&prune-group='+confirm(msg)
(awhen (borderline-unpreferred-group user doc) ; => returns 'Health'
(addjsarg
(+ default "&group=" it)
; default contains the url params constructed so far
(check-with-user
(+ "I will stop showing any articles about\\n"
" " uncamelcase.it "\\n"
"in this channel. (press 'cancel' to keep showing them)")
"prune-group"))))
Alternatively, couldn't you use JavaScript to dynamically generate itself? You could even write it in sexps if you really wanted to using JS arrays [1]. This is not meant as a critique of your approach but rather as an observation of JS's expressiveness and of the fact that much logic (not all, and maybe not in this particular case) can be implemented client-side or server-side with only subtle differences in the end result.
Yeah I can imagine using js to generate js. But if I'm using arc on the server anyway it doesn't seem to make sense to hand off to a js compiler just to to code-generate js. When I need to generate event handlers I'm within the arc html code-generation. Or am I misunderstanding you?
Nope, you got it. :) You're right it wouldn't make sense in this case where the app is already based in Arc. If you were approaching the project again from scratch though, perhaps there would be a just-as-good implementation path that involves letting JS handle more of the logic.
Yes, or unless you think JS is missing some important feature. Macros come to mind (although I don't know if Ruby can help there).
I'm actually just learning JavaScript now and so far am quite impressed. I'd read before that JS is "lispy" but didn't anticipate it being so true that I could find myself with code like the following:
Just wrote myself a very barebones JS REPL as an exercise [http://evanrmurphy.com/repl.html]. The source is all in that file, just HTML and JS (only tested in Chrome). I can't resist borrowing from Arc wherever I go now, e.g.
function pr () {
for (i in arguments) {
document.write(arguments[i]); }
return arguments; }
is a utility for avoiding the verbosity of "document.write".