Arc Forumnew | comments | leaders | submit | rocketnia's commentslogin
1 point by rocketnia 5543 days ago | link | parent | on: Noobing with news.arc

It sounds like you're talking about what forums usually accomplish using the HTML "title" attribute. Doing it in JavaScript lets your bubble be more stylish, and there might even be a way to do stylish bubbles using just CSS (having a separate :hover style or something, with the regular style hiding the children), but "title" should be the easiest to try first:

  <a href="http:..." title="Agreed.">Ask so-and-so: ...</a>
Something you might find convenient here is Arc's 'ellipsize function, which shortens long strings and puts ... at the end.

-----

1 point by markkat 5543 days ago | link

Thanks. Struggling with it, but I'll keep at it. Will title really work if I am referencing a call to comment text? I'm going to give the :hover route a shot. Not too worried about style though. :)

Ellipsize will definitely come in handy. Thanks for the tip.

-----

3 points by rocketnia 5544 days ago | link | parent | on: [necro thread] Semi-Arc

I said I'd respond to the Semi-Arc thread two months ago ago. @_@ Now the thread's on the third page, and its comments are disabled, so I'm posting my response here in a new thread. (Submitting a discussion page as a link is probably really confusing, but oh well. ^_^;;; )

It took me this long to finally dust off my rough draft of this post and post it. It's not that impressive, but here it is:

---

After my comment at http://arclanguage.org/item?id=12553, I poked around to try to discover Semi-Arc's weaknesses.

I'm going to try out Semi-Arc right now. ^_^ I'm sure I'll have some error reports for you in a moment. Hopefully not too many! :-p

However, it turns out Semi-Arc has at least one difference that's too cool to remove, yet makes writing portable Arc code especially tricky:

  arc> (+ '(a b c) '(d e f)).2
  c
  arc> (read "(+ '(a b c) '(d e f)).2")
  ((+ '(a b c) '(d e f)) 2)
I like it, but I worry whether it's a bit inconsistent. Here are a few cases worth double-checking. See if any surprise you:

  arc> (readall "car.'(a b)")
  ((car '(a b)))
  arc> (readall "get.0.'(a b)")
  ((get 0.0) '(a b))
  arc> (let foo '(a b) get.0.foo)
  *** void variable: 0
    0: 0
    1: (get 0)
    2: ((get 0) foo)
  arc> (let foo '((a)) foo.0.0)
  *** not applicable: ((a))
    0: (#0:0:foo 0.0)
  arc> (read "'a.b")
  '(a b)
  arc> (read "'a.b.c")
  '((a b) c)
  arc> (read "'a:b")
  '(compose a b)
  arc> (read "'a:b.c")
  ('(compose a b) c)
  arc> 'a:b.0
  compose
Here's the Arc 3.1 output for comparison:

  arc> (readall "car.'(a b)")
  (car. (quote (a b)))
  arc> (readall "get.0.'(a b)")
  (get.0. (quote (a b)))
  arc> (let foo '(a b) get.0.foo)
  a
  arc> (let foo '((a)) foo.0.0)
  a
  arc> (read "'a.b")
  (quote a.b)
  arc> (read "'a.b.c")
  (quote a.b.c)
  arc> (read "'a:b")
  (quote a:b)
  arc> (read "'a:b.c")
  (quote a:b.c)
  arc> 'a:b.0
  a:b.0
Partly because of this difference, I don't expect to write any code that's portable between Arc and Semi-Arc. There are other important differences too, like the fact that in Semi-Arc, ((compose a b) c) isn't equivalent to (a (b c)) when 'a or 'b is a macro.

So I can't come up with test cases that Semi-Arc needs to pass. It's not the same language as Arc 3.1, and I think it's up to you, suzuki, to decide what to do with it.

-----

2 points by rocketnia 5545 days ago | link | parent | on: A Language Should Support the Future

I thought that could be confusing. XD In terms I was already using, what I mean is just a language that targets a platform other than its own runtime. I might have mentioned the language acting more like a compiler than a direct workhorse.

In fact, I expect that to be the way day-by-day scripting is done too; a seemingly direct syntax will instead accomplish its task by compiling itself to some better-equipped language and running that (in a separate process, for instance).

This sort of thing is already touched upon in Arc thanks to aw's Python and Perl generators. It's also the way HTML-and-JavaScript generators work, but they do it by necessity, whereas I like the idea of code generation as a pervasive design strategy.

-----

2 points by akkartik 5545 days ago | link

Isn't that the same as a language with a cross-compiler? Shouldn't the design of the language be independent of the design of the implementation? Or is the language designed to be easy to cross-compile? To a specific platform?

-----

1 point by rocketnia 5544 days ago | link

Isn't that the same as a language with a cross-compiler?

No and yes.

First, the no: A cross-compiler typically takes code designed to run on a specific language runtime and translates it to run on a different platform. These customizable languages would instead run on a platform whose implementation doesn't matter, and their libraries would let you generate programs to run on the platforms that do matter to you.

The yes is that many of the customizable language's code generation libraries are bound to actually be cross-compilers, since it's a natural way to introduce or improve support for several platforms at once. They might even let you compile certain abstractions to both the customizable language's runtime and a platform you're targeting, letting you use them both as part of the build and as part of the product. (Unit testing comes to mind.)

Furthermore, you can think of the customizable language's runtime as being its compiler, with all the language code just acting to extend it. This suggests the language's compiler targets whatever platform you tell it how to target, making it inherently a cross-compiler.

Shouldn't the design of the language be independent of the design of the implementation? Or is the language designed to be easy to cross-compile? To a specific platform?

Well... those are hard questions to interpret for this kind of language. XD I think each could answer those questions in its own way.

That said, I think the languages' built-in syntax and semantics should be reasonably extensible when that makes sense, so that fewer libraries need to be full compilers and more can just be extensions of a standard compiler. That probably has the side effects of exposing more implementation details than usual and making the language easy to cross-compile.

Come to think of it, there are some easier answers:

Should the implementation be hidden? When in doubt, no; don't make an arbitrary choice that'll disable future programmers who know better than we do.

Should we be talking about a specific platform? Not in general. :-p I recommend for the language to be designed together with its own standard language runtime platform, for interoperability's sake, but the point is for it to focus on targeting whatever platform you need it to target.

-----

2 points by akkartik 5544 days ago | link

"A cross-compiler typically takes code designed to run on a specific language runtime and translates it to run on a different platform."

I don't think that's a cross compiler. All compilers translate, and I don't know what you mean by 'code designed for a specific runtime'. I think a cross compiler is concerned with the native target platform.

"A cross compiler is a compiler capable of creating executable code for a platform other than the one on which the compiler is run." http://en.wikipedia.org/wiki/Cross_compiler

"These customizable languages would instead run on a platform whose implementation doesn't matter."

That sounds like a virtual machine - the interface is fixed but you don't know or care if your code will be interpreted or JIT compiled. Am I understanding you correctly?

-----

2 points by rocketnia 5544 days ago | link

Nope, you're not understanding me yet. XD I think the root of it is that when you ask whether a language that "targets a platform other than its runtime" is "the same as a language with a cross-compiler," you're misinterpreting what I mean by "target." Possibly "platform" too.

As for "platform," if there's something that's nontrivially programmable, I consider it to be a platform. The thing that establishes the identity of a platform is the range of programs that's possible staying within its own practical limitations and following its rules. Adding rules lets you make platforms that embody the features several platforms have in common, as when developing for multiple Web browsers. One platform can be a program running in another (like Arc in Racket), which means its space of possible programs is no bigger than its host's, but it may also have fewer limitations and rules than its host, thanks to new frameworks it introduces and new ways it implements its host's features. A platform can be another platform with extra assumptions made about its state, like the assumption that a particular other process is available to communicate with. This is a bit of a digression, and I'm sure I haven't found all the kinds of platform families, but I'll leave it here 'cause it's thought-provoking. :)

By the idea of a language "targeting" a platform, all I mean is for that language to be good for developing that platform's programs. For instance, a DSL in Arc might be better for writing JavaScript than JavaScript itself is, if only because of syntax differences. Generating a bit of code using that DSL is a good way for Arc to "target" JavaScript, but it isn't the same thing as compiling a whole Arc program into JavaScript.

However, given that DSL, it would be reasonable to develop JavaScript applications using nothing but the DSL, with just enough Arc code to handle importing the DSL library and outputting the resulting files. In this case, arguably, "the whole thing" is cross-compiled to JavaScript, with the DSL library acting as that that cross compiler. When doing this kind of programming, it's irrelevant whether Arc itself is a language with a cross compiler, 'cause we only need to run Arc on one machine, the development machine we're using to produce the JavaScript code.

But that kind of programming is exactly what the languages I'm talking about would focus on. The libraries would be syntax tools and compilers, and the applications would be written in mashed up DSLs. The techniques would apply to all these languages, regardless of how each of them was built internally.

(The techniques also apply to other existing languages, but the difference is that I think those languages have overall designs and philosophies that don't play well with this coding style.)

-----

2 points by rocketnia 5547 days ago | link | parent | on: Noobing with news.arc

For this:

  (mac updating(place ? expr t iff 'is . body)
    (w/uniq rhs
      `(let ,rhs ,expr
         (unless (,iff ,place ,rhs)
           (= ,place ,rhs)
           ,@body))))
You're evaluating the subexpressions of 'place twice, which isn't necessary thanks to 'setforms. Also, I like to have macros macro-expand and evaluate their parameters from left to right if I can, just for similarity with 'do. (I still try to evaluate only as much as I need to though.) To accomplish these things, I'd go with this (untested) implementation instead:

  (def fn-updating (current-val setter-getter new-val comparator body)
    (unless (do.comparator current-val new-val)
      (.new-val:do.setter-getter)
      (do.body)))
  
  (mac updating (place ? expr t iff 'is . body)
    (let (binds val setter) setforms.place
      `(withs ,binds
         (fn-updating ,val (fn () ,setter) ,expr ,iff (fn () ,@body)))))
In the meantime, for the purposes of dates, I'd at least use 'iso instead of 'is. You're probably not going to get the same (date) list as one you have from earlier today. Even if (date) itself made that guarantee, you've potentially persisted and un-persisted the user data today.

In fact, since you've already made 'iso extensible, I'd use it as the default instead of 'is.

-----

1 point by akkartik 5547 days ago | link

All great points, thanks! I have in fact stopped using is everywhere in my code, don't know what I was thinking.

-----

1 point by akkartik 5546 days ago | link

Why the do's?

And what does the .new-val do?

-----

3 points by rocketnia 5546 days ago | link

Saying (do.foo ...) instead of (foo ...) just makes it so that 'foo isn't in function position. That means the local variable 'foo will always be used instead of some macro named 'foo that happened to be defined in another library.

The ssyntaxes .foo and !foo are short for get.foo and get!foo. Also, a:b ssyntax is handled before a.b ssyntax, giving the : lower precedence.

That means (.new-val:do.setter-getter) compiles as though it's ((get new-val) ((do setter-getter))), which makes it a roundabout way to accomplish ((do.setter-getter) new-val) with one less pair of parentheses, one less character, or (by my count) one less token.

It's really sort of silly in this case, since you save on so little while rearranging so much. In its favor, he (.a:b ...) idiom makes a bit more sense when it's a field/element access like (!width:get-rect ...) or (!2:setforms ...). It's especially helpful when it's part of a big chain of composed forms like (.a:b:.c:.d:e ...).

In my own code, including Lathe, I define this:

  (def call (x . args)
    (apply x args))
Then the code is just call.setter-getter.new-val, giving a savings of two characters, two pairs of parentheses, or (by my count) four tokens, all without causing the expressions to be rearranged.

Seems like a lot of brevity boilerplate, huh? :-p

-----

2 points by aw 5546 days ago | link

Saying (do.foo ...) instead of (foo ...) just makes it so that 'foo isn't in function position. That means the local variable 'foo will always be used instead of some macro named 'foo that happened to be defined in another library.

I remembered talking about this once and found the comment: http://arclanguage.org/item?id=11697

It looks like it would be an easy change to Arc to have local variables take precedence, though I haven't tried the patch myself.

-----

1 point by akkartik 5546 days ago | link

Oh nice. So is there a way using this trick to do

  a."b".c.d.g
without parens?

-----

3 points by rocketnia 5546 days ago | link

Not in Arc. The best you get is (.g:.d:.c:a "b"), I think. You can shove "b" into ssyntax with string!b, but you need to use it as an argument somehow, and any ssyntax containing .string!b will pass the 'string function itself as an argument instead of calling it first.

Of course, if "b" were a symbol instead of a string, it would just be "a!b.c.d.g".

In Penknife, the answer to your question is actually yes: It's "q.b'a.c.d.g", where q is the string-quoting operator and ' is an operator that acts like a reverse a.b. It's easy to stump Penknife too, but I'm hoping to make a full thread about Penknife's take on infix operators in a couple of days or so.

-----

2 points by thaddeus 5543 days ago | link

Optionally, in ac.scm:

  (define (has-ssyntax-char? string i)
    (and (>= i 0)
         (or (let ((c (string-ref string i)))
               (or (eqv? c #\:) (eqv? c #\~) 
                   (eqv? c #\&)                
                   (eqv? c #\%)                
                   ;(eqv? c #\_) 
                   (eqv? c #\.)(eqv? c #\!)))
             (has-ssyntax-char? string (- i 1)))))

  (define (expand-ssyntax sym)
    ((cond ((or (insym? #\: sym) (insym? #\~ sym)) expand-compose)
           ((or (insym? #\. sym) (insym? #\! sym)(insym? #\% sym)) expand-sexpr)
           ((insym? #\& sym) expand-and)
       ;   ((insym? #\_ sym) expand-curry)
           (#t (error "Unknown ssyntax" sym)))
   sym))

  (define (build-sexpr toks orig)
    (cond ((null? toks)
           'get)	    
          ((null? (cdr toks))
           (chars->value (car toks)))
          (#t
           (list (build-sexpr (cddr toks) orig)
                 (cond ((eqv? (cadr toks) #\!)
                        (list 'quote (chars->value (car toks))))
                       ((eqv? (cadr toks) #\%)
                         (list 'string (list 'quote (chars->value (car toks)))))
                       ((or (eqv? (car toks) #\.)(eqv? (car toks) #\!)(eqv? (car toks) #\$)(eqv? (car toks) #\%))
                         (err "Bad ssyntax" orig))
                       (#t 
                       (chars->value (car toks))))))))
Then:

  arc> (= test (obj "a" "my a val" "b" "my b val"))
  #hash(("a" . "my a val") ("b" . "my b val"))

  arc> test%a
  "my a val"
[edit: actually, it would be nicer to have the percent symbol represent the spaces in the string and have some other symbol signify string handling, but I never got around to it + my scheme foo is lacking :)]

-----

1 point by akkartik 5546 days ago | link

Is fn-updating generally useful?

-----


With "var bar = function() { ... };", I bet you run into self-recursion issues. Unless I'm mistaken, the variable "bar" isn't in the scope of the closure.

At the very least, (def bar ...) and (def foo ...) won't be corecursive, since foo isn't in bar's scope. That in particular is what the "function bar() { ... }" syntax is for. ^_^ I believe that kind of statement assigns to a variable that's implicitly declared at the top of the current scope, meaning it's visible to itself and all the other functions declared that way, without the need for a "var bar, foo; bar = ...; foo = ...;" idiom.

makes some nice abstractions for you, like always guaranteeing lexical scope

For me, that's one of those "why would I ever want the language to do this for me" things. ^_- Maybe this means I'm a Blub programmer, but I prefer explicitly declaring the new scope's variables rather than explicitly declaring which variables I take from the outer scope.

Declaring only globals is the worst, 'cause it implies not being able to shadow a local with another local of the same name. Ever since 'it, '_, and 'self, I've been accustomed to using the same variable names over and over, even in nesting scopes. Shame on me, but still. :-p

You can probably disregard most of this rant, 'cause it's probably just as annoying either way. XD Maybe someone else has an opinion though.

-----

1 point by evanrmurphy 5549 days ago | link

> With "var bar = function() { ... };", I bet you run into self-recursion issues. Unless I'm mistaken, the variable "bar" isn't in the scope of the closure.

You're right, thanks for the correction. There is an alternative to the "function bar() { ... }" syntax that allows for recursion, though:

  var bar;
  bar = function() {
    ...
  };
This is how CoffeeScript compiles function definitions, and it's what I meant to write. I'm not really sure yet about all the advantages and disadvantages when compared to the other format.

> You can probably disregard most of this rant, 'cause it's probably just as annoying either way.

Your rants are always welcome here! ^_^

---

Update: Sorry, rocketnia. Reading your comment more carefully I see you already talked about this:

> I believe that kind of statement assigns to a variable that's implicitly declared at the top of the current scope, meaning it's visible to itself and all the other functions declared that way, without the need for a "var bar, foo; bar = ...; foo = ...;" idiom.

I guess whether you use the explicit var declaration is largely a matter of taste. Declaring all variables explicitly at the top of the scope more transparent, but less concise. I suppose since CoffeeScript tends to declare other variables at the top of the scope, including functions variables in that group allows for a certain consistency.

-----

1 point by evanrmurphy 5539 days ago | link

> With "var bar = function() { ... };", I bet you run into self-recursion issues. Unless I'm mistaken, the variable "bar" isn't in the scope of the closure. At the very least, (def bar ...) and (def foo ...) won't be corecursive, since foo isn't in bar's scope.

Actually, both of these cases are working fine for me with the ``var bar = function() {...};`` format. This is testing in Chrome 5 on Linux:

  // recursion

  var foo = function(x) { 
    if (x == 0) 
      return "done"; 
    else 
      return foo(x - 1); 
  };

  foo(5)
  // => "done" 

  // corecursion

  var foo = function(x) { 
    if (x == 0) 
      return "done"; 
    else 
      return bar(x - 1); 
  };

  var bar = function(x) { 
    if (x == 0) 
      return "done"; 
    else 
      return foo(x - 1); 
  };

  foo(5)
  // => "done"
  bar(5)
  // => "done"
Am I missing something here?

-----

1 point by rocketnia 5538 days ago | link

Actually, you're right. ^^; In JavaScript, all variables declared in a function are visible throughout the function, even before the declaration statement.

  var foo = 4;
  
  (function(){
    alert( foo );  // "undefined"
    var foo = 2;
  })();
My mistake. ^_^;

-----

1 point by evanrmurphy 5549 days ago | link

> why would I ever want the language to do this for me

Hmm... so would you also prefer that return statements never be implicit?

I'd like to design the bottom layer operators of this compiler to have a one-to-one correspondence with JavaScript and zero automagic. This means explicit var declarations, explicit returns and an embrace of the expression/statement dichotomy. Then, we should be able to layer on top all desired forms of automagic using macros so that programmers can opt-in or opt-out as they like.

Or is it really naive to think it could work out this way? :P

-----

2 points by rocketnia 5549 days ago | link

Nah, that comment was only about function scope. I'm saying I really prefer the kind of scoping Arc and JavaScript both have, where variables shadow each other and closed-over variables don't need to be declared (but local ones do). I can't put my finger on why... but wait, pg can. :D

http://www.paulgraham.com/arclessons.html

Skip to "Implicit local variables conflict with macros."

As for implicit return statements, I don't know what you expect me to be, but I'm for them. ^_^ I think you can always say "return undefined;" in JavaScript to accomplish the same thing as leaving out the return statement, so in a way, leaving the return statement out is just syntactic sugar.

I'm for explicit return statements too, for the purposes of short-circuiting. However, they probably won't play well with macros, for the same reason as pg encountered with implicit local variables: Lexical scope boundaries might pop up in unexpected places and change the meaning of "return;".

> Or is it really naive to think it could work out this way? :P

Well, I do have lots of suggestions. They go pretty deep into the fundamental design too. That said, they sort of lead to not programming in Arc. You'll see what I mean in a second (unless I go scatterbrained on ya again).

I think it would be best to treat this as a combinator library. You can have utilities that build not only JavaScript expressions and statements,* but also other intermediate forms, like lists of statements. I wouldn't be surprised to see http://en.wikipedia.org/wiki/Control_flow_graph pop up at some point. As the combinator library goes on, it can introduce more convenient construction syntaxes, including full DSLs.

If this is beginning to sound similar to the topic I just posted, "A Language Should Target Moving Platforms"[1], that's because it is. We're talking about generating JavaScript code. It's very closely related to the topic of generating code in general. :-p

I was developing Penknife not too long ago. It's a language much like Arc, but what's important here is that its expressions are compiled and macro-expanded to an intermediate format first--i.e. parsed into an AST--and it's easy to make closures whose ASTs can be inspected. My plan is for the Penknife AST itself to be extensible using user-defined types, and my goal is for non-Penknife ASTs to be made using the same syntax technology used elsewhere in Penknife, right down to using the same compiler.

So yeah, this is my apprach to a JavaScript DSL. ^_^ I don't expect you to go adopt the whole approach, but if you do want to pursue it, or if there's some aspect of it that would fit into your design too, be my guest.

* Fine-grained control is fine by me. :-p So is automagic. I want it all!

[1] http://arclanguage.org/item?id=12939

-----

1 point by akkartik 5549 days ago | link

"Lexical scope boundaries might pop up in unexpected places and change the meaning of "return;"."

I couldn't believe this, but I looked around and yes, it's true, "..the scope container in javascript is a function." (http://mark-story.com/posts/view/picking-up-javascript-closu...)

That seems bad. Don't create a new function in js everytime I do a let in arc. But I don't know if you can avoid doing so.

Perhaps one way to do it would be to play a little fast and loose with semantics. Assume let translates to the scope of the containing function.

-----

1 point by evanrmurphy 5549 days ago | link

> I couldn't believe this, but I looked around and yes, it's true, "..the scope container in javascript is a function."

Yep! Function scope + no tail-call optimization = a formidable challenge. ^_^

> Perhaps one way to do it would be to play a little fast and loose with semantics. Assume let translates to the scope of the containing function.

Interesting approach. I'll play around with this. There might also be weird hacks that could simulate let without costing a whole function on the stack. For example, you might be able to get away with something like this:

  (let x 5         var _temp = true;
    ... )          while (_temp) {
                     _temp = false;
                     var x = 5;
                     ...
                   }
Or this:

  (let x 5         var _temp = true;
    ... )          for (var x = 5; _temp = false; _temp)                           
                     ...
                   }
But I'm not sure yet if these work, or if they're less expensive than the straightforward let translation:

  (let x 5         (function() {
    ... )            var x = 5;
                     ...
                   }).call(this);

-----

2 points by rocketnia 5548 days ago | link

I tried these out, and they don't seem to help, at least in Chrome:

  var x = 1;
  {
      var x = 2;
      var y = "but why!?";
      alert( x );           // 2
  }
  alert( x );               // 2
  alert( y );               // but why!?
  
  var x = 1;
  do
  {
      var x = 2;
      var y = "but why!?";
      alert( x );           // 2
  }
  while( false );
  alert( x );               // 2
  alert( y );               // but why!?
The next thing you might try is mangling variable names. If you expect the JavaScript code to never use threads (which it doesn't, I think), you could temporarily replace the variable values using assignment.

For a high-level (and non-idiomatic) approach, it's possible to implement trampolining using exceptions. I've done it in about a page of JavaScript (right next to my Fermat's Last Theorem proof, of course of course :-p ), and I think the API can be as simple as this:

  - Use bounce( foo, foo.bar, 1, 2 ,3 ) instead of
      foo.bar( 1, 2, 3 ) in tail positions. This throws an
      exception containing information about the next call
      to make.
  - To begin a trampolining loop, call the function with
      trampoline( foo, foo.bar, 1, 2, 3 ). This should be
      done when calling functions at the top level and when
      calling functions from within functions that are to be
      exposed to other JavaScript utilities and DOM event
      handlers (which won't call trampoline themselves).
Okay, so determining when a closure could "escape" into the outside world might be hard. O_o To avoid that trouble, uh, keep a global variable saying that a trampolining loop is already in progress, and use trampoline( ... ) for almost every single call? Well, that'll complicate things a little. ^_^;

-----

1 point by evanrmurphy 5548 days ago | link

> The next thing you might try is mangling variable names.

I think this could work pretty nicely, actually:

  (let x 5         var _x;
    ... )          _x = 5;
                   ...
Here's an example with a global and local variable:

  (= x 6)            var x, _x;
  (let x 5           x = 6;
    (alert x))       
  (alert x)          _x = 5;
                     alert(_x); // => 5

                     alert(x); // => 6
If you use multiple lets with the same variable name in one scope, you would need to differentiate with additional underscores or something:

  (let x 5           var _x, __x;
    (alert x))         
  (let x 6           _x = 5;
    (alert x))       alert(_x); // => 5

                     __x = 6;
                     alert(__x); // => 6
Of course, there is still some risk of variable name collision, and the output isn't super readable. Maybe it's good to have two operators, `let` and `let!`. The former uses function scope, so it's safer and compiles to more readable JavaScript, but it increases the stack size. The latter (let!) is the optimized version that uses one of the schemes we've been talking about.

-----

1 point by rocketnia 5548 days ago | link

What's your policy regarding the ability for people to say (let _x 5 ...) to spoof the mangler? ;) Also, will the name "let!" conflict with ssyntax?

These questions shouldn't keep anyone up nights, but I thought I'd point them out.

-----

1 point by evanrmurphy 5548 days ago | link

> What's your policy regarding the ability for people to say (let _x 5 ...) to spoof the mangler? ;)

The underscore prefix system would be nice because it's pretty readable, but it's not necessary. In the worst case, we can use gensyms. I thought using underscores for internal variables might work because CoffeeScript does it [1], but maybe it won't. So you raise a good point. :)

> Also, will the name "let!" conflict with ssyntax?

Yes. I'm starting from scratch with the ssyntax. `!` is a regular character now. It can be used in names like `let!`, and when by itself in functional position it compiles to the JavaScript negation operator:

  (! x)   =>   !x
`.`, `:`, `~`, `[]`, `&` and friends are out, too. This may displease my Arc buddies, but I just found it too difficult to think in JavaScript when the gap in meaning between Arc and JS for these characters was so large. `.` compiles to the JS dot operator now, `{}` to the JS object literal and `[]` to the array literal (see [2] for some details). Note that quote ('), quasiquote (`), unquote (,), unquote-splicing (,@) and string quoting (") should all work as expected.

---

[1] http://jashkenas.github.com/coffee-script/#comprehensions

[2] http://arclanguage.org/item?id=12948

-----

1 point by akkartik 5549 days ago | link

Probably just different aesthetics. I sense that you're thinking in javascript and rocketnia is thinking in arc.

-----

2 points by rocketnia 5550 days ago | link | parent | on: Pattern matching

I disagree with that change. You've made this...

  (:type var '(unsigned-byte 32))
...do what this used to do...

  (:type var (lambda (x) (typep x '(unsigned-byte 32))))
...but I don't think there's a replacement for this:

  (:type var (lambda (x) (and (numberp x) (<= 10 x))))
Maybe you should have both a (:type var 'symbol) form and a (:test var #'symbolp) form. ^_^

-----


Sounds a lot like http://practical-scheme.net/wiliki/arcxref, but more mature, not for Arc, and not, well, dead. >.>

Hey, I have a wild idea. Anarki's the most active Arc community project, right? Why not make a GitHub Pages site for Arc and let it be public-push?

-----

3 points by aw 5550 days ago | link

I actually tried GitHub Pages for awwx.ws before I changed to hosting it myself. I don't know if this is still true, but at the time they rendered pages as a batch process: I'd make a change, and some indeterminate time later -- sometimes immediately, sometimes after a long delay -- the change would appear on my web site. I found this killed my productivity.

At this point I'm willing to put in the time to implement a solution that works the way I want it to.

However I wouldn't discourage anyone from setting up a GitHub Pages for Arc today. I hope that my site will turn out to better than GitHub Pages (for this particular purpose), but that doesn't mean that you need to wait around for me to implement something, or even necessarily that you will in fact find my site better than GitHub Pages.

Anything that gets published on GitHub Pages I can import into my site when I actually have something written, so any work you do now in GitHub Pages won't be lost if it turns out that my site does work better. And GitHub Pages are really easy to use and get started with, so there isn't a big time investment needed there either.

-----

1 point by evanrmurphy 5550 days ago | link

> Hey, I have a wild idea. Anarki's the most active Arc community project, right? Why not make a GitHub Pages site for Arc and let it be public-push?

You could get pretty far with that and Github gists. Except that they don't do syntax highlighting for Arc: https://gist.github.com/729894

-----

1 point by rocketnia 5551 days ago | link | parent | on: Pattern matching

I did, but then my computer ate it! ><;; Sorry, I don't think I have time to try again. Maybe someone else will?

Here's a bit of a Rosetta Stone to help you out, or at least to give you an idea of how it would look:

  ; Common Lisp
  (let* ((a #'list)
         (b 1)
         (c 2))
    (begin nil
      (cond
        (a (funcall a 3 4 5))
        (b (return-from nil nil))
        (t 6))))
  
  ; Arc
  (withs (a list
          b 1
          c 2)
    (point foo
      (if a (a 3 4 5)
          b (foo nil)
            6)))
The rest should be a straightforward process of finding Arc functions that do the same things as the Common Lisp functions do. Here are some useful links for that: http://files.arcfn.com/doc/ http://files.arcfn.com/doc/fnindex.html They're a bit out-of-date in a couple of places though. :/

-----

3 points by rocketnia 5552 days ago | link | parent | on: Extend Arc's ssyntax?

Changing ac.scm's 'expand-ssyntax will make Arc's 'ssyntax predicate incorrect. The exception should be added in here, where there happen to already be a few exceptions that are currently meaningless:

  (define (ssyntax? x)
    (and (symbol? x)
         (not (or (eqv? x '+) (eqv? x '++) (eqv? x '_)))
         (let ((name (symbol->string x)))
           (has-ssyntax-char? name (- (string-length name) 1)))))
(This is quoted from Anarki 'cause the source is handier for me right now.)

Note, however, that calling Arc's 'ssexpand will expand a symbol regardless of whether it's an exception. I don't know whether this is a bug or not; the workaround is just to check with 'ssyntax first if it matters.

-----

1 point by evanrmurphy 5550 days ago | link

Thanks for the tip, this is working well. The only minor issue I'm still dealing with on this is how to strip the dot of all special meaning except in the context of rest parameters.

By adding the dot ssyntax exception in ac and not applying the read-normal macro from the OP to #\., I've gotten this to work so long as dot is inside the scheme bars:

  ; Dot treated as a symbol when inside the bars

  arc> (= |.| 2)
  2
  arc> (is (+ 1 1) |.|)
  t

  ; It still works in the rest parameter context

  arc> (def foo (x . args)
         `(,x ,@args d))
  #<procedure: foo>
  arc> (foo 'a 'b 'c)
  (a b c d)

  ; But it doesn't work as a symbol without the bars.
  ; Note that (read-normal #\.) can make this work but
  ; it breaks the rest parameter case.

  arc> (= . 2)
  Error: "map: expects type <proper list> as 2nd argument,
  given: 2; other arguments were: #<procedure:ac-niltree>"
So I'm about 3/4 of the way there. :)

-----

4 points by rocketnia 5553 days ago | link | parent | on: Share your useful functions/macros

My 'xloop at http://github.com/rocketnia/lathe has a more convenient interface at the expense of overall simplicity. It supports the usual syntax, but it also lets you leave off the parentheses as long as the things you're binding to are non-nil, non-ssyntax symbols, like most variable names are.

  (xloop i 1 total 1
    (if (> i n)
      total
      (next (+ i 1) (* total i))))
The restriction on the bindings makes it possible to figure out where the body starts.

-----

More