Arc Forumnew | comments | leaders | submit | evanrmurphy's commentslogin
1 point by evanrmurphy 5593 days ago | link | parent | on: Why isn't copylist tail-recursive?

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

I don't see any reason why we can't have both.

-----

2 points by akkartik 5593 days ago | link

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.

-----

2 points by evanrmurphy 5593 days ago | link | parent | on: Why isn't copylist tail-recursive?

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

-----

2 points by akkartik 5593 days ago | link

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

-----

3 points by evanrmurphy 5595 days ago | link | parent | on: 'disktem

How does 'temloadall play into this? Would you need a "'disktem-all" using that instead of 'temload to cover all the cases?

-----

2 points by evanrmurphy 5595 days ago | link | parent | on: 'disktem

Hmmm... I was going to say it'd be nicer to put that save function in its own utility for a tidier 'disktem:

  (def temsave (tem file)
    (writefile (tablist tem) file))

  (mac disktem (var tem file)
    `(fromdisk ,var ,file (inst ',tem) [temload ',tem _] temsave))
Which you can do, but that 'temsave is isomorphic to (the already-existing) 'save-table:

  (def save-table (h file)
    (writefile (tablist h) file))
So could 'disktem be rewritten as the following?

  (mac disktem (var tem file)
    `(fromdisk ,var ,file (inst ',tem) [temload ',tem _] save-table))
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!

-----

1 point by evanrmurphy 5593 days ago | link

Minor revision of that last 'disktem definition:

  (mac disktem (var tem file)
    `(fromdisk ,var ,file (inst ,tem) [temload ,tem _] save-table))
The only difference is ,tem instead of ',tem for consistency with the other template utilities, which don't quote it.

Did more testing and the reliability seems good, in case anyone else wants this big ol' wart for their own arc's face. ;)

-----

1 point by evanrmurphy 5596 days ago | link | parent | on: 'wipeop

Here's a version that takes any number of arguments:

  (mac wipeop names
    `(do ,@(map (fn (_)
                  `(defop ,_ ()
                     (pr nil)))
                  names)))

-----

1 point by evanrmurphy 5596 days ago | link | parent | on: 'wipeop

Just realized you can get the same effect without initializing the optional arg:

  (mac wipeop (name (o msg))
    `(defop ,name ()
      (pr ,msg)))

-----

2 points by akkartik 5596 days ago | link

Or even just:

  (def wipeop (op) (wipe srvops*.op))
You'll have to quote the name, but that seems a minor inconvenience.

-----

4 points by evanrmurphy 5596 days ago | link

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.

-----

1 point by akkartik 5596 days ago | link

Actually not trivial at all. I agree with you.

-----

1 point by evanrmurphy 5596 days ago | link

Could even take that arg out altogether since all it's supposed to do is wipe:

  (mac wipeop (name)
    `(defop ,name ()
      (pr nil)))
There, now it's an even babier macro. ;)

-----


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

-----

1 point by evanrmurphy 5608 days ago | link | parent | on: Negative indexes for strings

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.

-----

2 points by fallintothis 5608 days ago | link

  arc> (ssexpand 'xs.-1)
  (xs -1)
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

-----

1 point by evanrmurphy 5608 days ago | link

Glad the 'ssexpand works, I should have tried that.

Python's indexing doesn't wrap around infinitely, but that doesn't mean Arc's couldn't.

-----

1 point by fallintothis 5608 days ago | link

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.

-----

1 point by evanrmurphy 5608 days ago | link

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

-----

1 point by evanrmurphy 5611 days ago | link | parent | on: Arc to JavaScript translator?

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?

-----

1 point by akkartik 5611 days ago | link

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.

-----

1 point by evanrmurphy 5611 days ago | link | parent | on: Arc to JavaScript translator?

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"?).

-----

1 point by conanite 5611 days ago | link

RJS does this for ruby ... i confess i've never seen the point, unless you really, really don't want to learn js :)

-----

2 points by akkartik 5610 days ago | link

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"))))
Helpers:

  ; url+'param='+confirm('msg')
  (def check-with-user(msg param)
    (+ "'" param "='" " + "
       "confirm('" jsesc.msg "')"))

  (def addjsarg(l arg)
    (+ "'" l "&' + "
       arg))

-----

1 point by evanrmurphy 5610 days ago | link

Thanks for sharing your code.

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.

[1] http://www.crockford.com/javascript/little.html

-----

1 point by akkartik 5610 days ago | link

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?

-----

1 point by evanrmurphy 5610 days ago | link

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.

-----

1 point by evanrmurphy 5610 days ago | link

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:

    (function add1 (_) {
       return (1 + _); })
       (1);                    // => 2
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".

-----

More