Arc Forumnew | comments | leaders | submit | Pauan's commentslogin
1 point by Pauan 5470 days ago | link | parent | on: New wart interpreter: lisp-1, fexprs

I'll note that in my code I frequently have to use errsafe, because the thing may not be a cons. For instance, suppose you had a table called "foo". I've been using this pattern a lot recently:

  (if (foo:car x) ...)
But that will break if x isn't a cons, so I have to do this:

  (if (errsafe:foo:car x) ...)
So I don't think it's necessarily a bad idea for car/cdr to return a value rather than throw an error... but I can see why some people would prefer it to throw an error. For me personally, I think my code would benefit more from car/cdr returning nil, rather than throwing an error.

-----

1 point by rocketnia 5470 days ago | link

I'd use this:

  (if (foo acons&car.x) ...)
...except maybe I wouldn't, 'cause I think Rainbow treats a&b.c as (andf a b.c).

-----

3 points by Pauan 5471 days ago | link | parent | on: New wart interpreter: lisp-1, fexprs

"and evanrmurphy for getting me thinking about fexprs[2]"

I've been coming to the conclusion that although macros are great, they have some pretty severe limitations, due to them always being expanded at compile-time. So I'd be very interested to see if fexprs would be a good fit for Arc.

What I think would be neat is if macros were expanded at compile-time as much as possible, and when they can't be expanded at compile-time, they'll revert back to interpreting at run-time. Then, you can get full macro speed most of the time, but it would still allow you to do things like, say, use `apply` on a macro, or pass it as an argument to `map`, etc.

Alternatively, you could just not have macros, only having fexprs, and then try to optimize fexprs in various ways. I doubt it'd be as fast as expanding macros at compile-time, but... who knows, it might still be Fast Enough(tm).

Anyways, I think it's good for us to experiment with fexprs more, and see how things turn out.

---

In fact, because of the severe problems with macros, I independently came up with a pattern that rocketnia had already discovered: thunks. By wrapping every argument to a function in a thunk, you basically turn them into ghetto fexprs. So rather than doing this:

  (foo a b c)
You'd do this:

  (foo (fn () a) (fn () b) (fn () c))
But obviously that's a total pain, so what I did was rename "foo" to "foofn", and then have a macro called "foo". So that way, this:

  (foo a b c)
Would expand into this:

  (foofn (fn () a) (fn () b) (fn () c))
As near as I can tell, this is pretty much hygienic macros, since foofn is an ordinary function that has lexical scope. It's not nearly as clean or expressive as fexprs, but it's a cool little hack that can help work around the limitations of macros.

But, if we get to the point where a significant number of macros are basically just expanding into thunks... then I think we'd be better off having fexprs.

-----

2 points by bogomipz 5469 days ago | link

About thunks; this is actually a situation where statically typed languages have the potential to do something interesting that is hard in dynamically typed systems.

If foo takes an argument that should be a zero arity function that returns a number, and you write:

  (foo (+ x y))
The compiler could recognize that the expression you used for the argument can be converted into a function with the correct signature. I think I have heard of languages on the JVM that do this, not sure which.

Also note that Smalltalk-80 is very much designed around the principle of thunks. E.g:

  a > b ifTrue: [Transcript show: 'A is great!']

-----

1 point by Pauan 5471 days ago | link | parent | on: New wart interpreter: lisp-1, fexprs

"[5] What's more, it sucks to use up '|' for such an infrequently-used feature."

Yeah, I agree. When I want a symbol with weird characters in it, I'd rather just escape it, like so:

  foo\ bar
Instead of:

  |foo bar|
The biggest reason I've found for using symbols with odd characters is when I'm using them as string substitutes. For instance, in a hypothetical Arc library that parses stuff, you might want to be able to write this:

  (prefix new ...
          !   ...
          ~   ...
          +   ...
          -   ...)
Rather than this:

  (prefix "new" ...
          "!"   ...
          "~"   ...
          "+"   ...
          "-"   ...)
Just looks a lot cleaner. Aside from that, I haven't had much reason to use || or symbol escapes... besides abusing it for fun, of course:

  (def |(prn "hello world")| ()
    (prn "goodbye world"))

  (|(prn "hello world")|) -> "goodbye world"

-----

1 point by akkartik 5471 days ago | link

Yeah there's a whole series of articles about symbol abuse at http://kazimirmajorinc.blogspot.com (at and just before http://kazimirmajorinc.blogspot.com/2011/07/implementing-dat...)

-----

1 point by akkartik 5470 days ago | link

  (prefix new ...
          !   ...
          ~   ...
          +   ...
          -   ...)
You should be able to just do that without any sym-escaping, right? Perhaps quote should suppress ssyntax expansion?

The only reason for escaping seems to be spaces. And really weird characters like quotes.

-----

1 point by Pauan 5470 days ago | link

"The only reason for escaping seems to be spaces. And really weird characters like quotes."

Yes. For instance, in arc2js:

  (prefix    new     new\      17
             del     delete\   15
             no      !         14)

  (bin       mod     %         13
             and     &&        5
             or      \|\|      3)

  (binsep    do      \,        1)
Note the escape for , and || and spaces. I still find this much more readable than using strings. But you don't need || for that... you can just use \ escaping. So I think it's a very good idea to free up || for something else.

---

As for preventing ssyntax expansion... right now, ssyntax is handled in arc.arc, so it's only expanded if you explicitly call ssexpand (or if a function like setforms calls ssexpand)... so in the example above, I simply don't call "ssexpand", and it all works out fine.

However, if ssyntax were handled by the reader, then there should definitely be a way to prevent it from expanding... quote might be a good way of doing that.

-----

1 point by rocketnia 5470 days ago | link

"I still find this much more readable than using strings."

I don't! XD I don't have a problem with you finding it readable, but for me, if I have something with spaces in it, especially if the space is at the end, I surround it with some kind of delimiter:

  (prefix    new     "new "    17 ...)
  (prefix    new     |new |    17 ...)
That way if I write my code this way...

  (prefix new new\  17
          del delete\  15
          no ! 14)
...then I won't be tempted to "fix" the stray whitespace to this:

  (prefix new new\ 17
          del delete\ 15
          no ! 14)
In fact, I don't think I use \ at all, and sometimes I've thought it could be cool to free up for something else. It is a non-shifted punctuation mark.

-----

1 point by Pauan 5470 days ago | link

"In fact, I don't think I use \ at all, and sometimes I've thought it could be cool to free up for something else. It is a non-shifted punctuation mark."

Yeah, but... \ is already used in strings for escaping, so using it for symbol escaping is quite natural (read: consistent). If we freed up \ then how would we escape symbols? Unless you're saying symbols shouldn't be escaped, and we should be limited in the number of things we can put into a symbol...

-----

1 point by rocketnia 5470 days ago | link

"If we freed up \ then how would we escape symbols?"

We'd escape them with ||. Inside ||, we could still use \ for escaping things like |, even if it doesn't have that meaning on the outside.

-----

1 point by Pauan 5470 days ago | link

No no no, the whole point is that we're trying to free up | because it's a useful character... more useful than \ in my opinion, especially since \ is so incredibly commonly used for escaping.

-----

1 point by rocketnia 5467 days ago | link

Then how about using \ as a delimiter?

  (prefix new \new \ 17
          del \delete \ 15
          no ! 14)
To reiterate a bit, the reason I wouldn't use \ the way you do is that "\ " at the end of a symbol makes the space blend in with the whitespace around it. For an example other than this one, consider that putting such a symbol at the end of a line might introduce bugs when people remove all trailing whitespace in a file.

-----

2 points by Pauan 5467 days ago | link

"Then how about using \ as a delimiter?"

As said, that's totally inconsistent with the way that \ works everywhere else, including within strings. I'm not entirely sure how to fix this problem adequately without keeping | in the language.

But... you did mention making strings and symbols identical... then we would just use "" to delimit symbols with strange characters in them. Of course then we'd be giving up mutable strings, but is that really so bad? That's how we use them most of the time anyways. I actually rather like that idea. It would also make (is "foo" "foo") consistent, whereas right now it isn't.

But... this has some amusing implications. I had mentioned earlier that I wanted to make strings identical to a list of characters... so you can call car and cdr on a string. But if strings and symbols are identical, then that basically means symbols would be... a list of characters. So, symbols would be mutable. And (car 'foo) would be #\f. And symbols would no longer be interned... Pretty crazy stuff.

---

"To reiterate a bit, the reason I wouldn't use \ the way you do is that "\ " at the end of a symbol makes the space blend in with the whitespace around it. For an example other than this one, consider that putting such a symbol at the end of a line might introduce bugs when people remove all trailing whitespace in a file."

Yeah, I know. I just decided that for my particular use case, I was willing to accept the practical disadvantage in exchange for increased readability and one less character. To put it bluntly, I prefer the way "new\ " looks, compared to "|new |" I do agree that delimiters are overall better, though.

-----

1 point by rocketnia 5466 days ago | link

"totally inconsistent with the way that \ works everywhere else, including within strings"

Where else does it work, besides strings? Regexes? If you're talking about quoting code from other languages (not counting TeX and other not-so-C-inspired languages which already use backslash for other purposes :-p ), yes, it can be nice to have some consistency between layers of escaping.

Sometimes I really don't like the exponential growth that results from that:

  ""
  "\"\""
  "\"\\\"\\\"\""
  "\"\\\"\\\\\\\"\\\\\\\"\\\"\""
  "\"\\\"\\\\\\\"\\\\\\\\\\\\\\\"\\\\\\\\\\\\\\\"\\\\\\\"\\\"\""
  "\"\\\"\\\\\\\"\\\\\\\\\\\\\\\"\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"\\\\\\\\\\\\\\\"\\\\\\\"\\\"\""
Well, It's not quite as bad as that. If we have \x escapes, it can become quadratic:

  ""
  "\"\""
  "\"\\\"\\\"\""
  "\"\\\"\\\\x22\\\\x22\\\"\""
  "\"\\\"\\\\x22\\\\x5Cx22\\\\x5Cx22\\\\x22\\\"\""
  "\"\\\"\\\\x22\\\\x5Cx22\\\\x5Cx5Cx22\\\\x5Cx5Cx22\\\\x5Cx22\\\\x22\\\"\""
And \u escapes (supported by JSON) become quadratic in the same way:

  ""
  "\"\""
  "\"\\\"\\\"\""
  "\"\\\"\\\\\\\"\\\\\\\"\\\"\""
  "\"\\\"\\\\\\\"\\\\\\\\u0022\\\\\\\\u0022\\\\\\\"\\\"\""
  "\"\\\"\\\\\\\"\\\\\\\\u0022\\\\\\\\u005Cu0022\\\\\\\\u005Cu0022\\\\\\\\u0022\\\\\\\"\\\"\""
IMO, it's too bad we don't just have quadratic growth from the start:

  ""
  "\q\q"
  "\q\-q\-q\q"
  "\q\-q\--q\--q\-q\q"
  "\q\-q\--q\---q\---q\--q\-q\q"
  "\q\-q\--q\---q\----q\----q\---q\--q\-q\q"
However, the exponential growth is a bit easier to keep track of than these quadratic options, I think, and that's a bit more important.

What I really think could be cool is for every language to be Penknife-like, with string syntaxes accepting any nested square brackets inside. Then we'd get to spend almost no editing effort and yet have linear growth:

  s[]
  s[s[]]
  s[s[s[]]]
  s[s[s[s[]]]]
  s[s[s[s[s[]]]]]
  s[s[s[s[s[s[]]]]]]
---

"But... you did mention making strings and symbols identical... then we would just use "" to delimit symbols with strange characters in them."

That's why I brought it up. Akkartik mentioned not reserving |, and I don't like the symbol-string divide anyway, so I figured it could kill two birds with one stone.

Actually there's another option. We can take advantage of the string syntax to write odd symbols using some kind of #s"hey, I'm a symbol" reader macro... at the cost of giving up #. (We could also use #s[hey, I'm a symbol].)

---

"we'd be giving up mutable strings"

Well, I did mention that I use strings as though they're immutable and interned. I do this mainly because of 'is comparing strings by content, and because I like the thought that every string literal reuses the same instance, but I also just don't see the point of mutating strings.

---

"I wanted to make strings identical to a list of characters [...] So, symbols would be mutable."

Yeah, I wouldn't suggest doing symbol=string and string=list at the same time. It's pretty crazy to have mutable symbols, since that makes them more confusing to use as hash table keys. Given the choice, I'd ditch string=list first (and I'm sure you expected me to say that).

-----

1 point by Pauan 5466 days ago | link

"Actually there's another option. We can take advantage of the string syntax to write odd symbols using some kind of #s"hey, I'm a symbol" reader macro... at the cost of giving up #. (We could also use #s[hey, I'm a symbol].)"

No, you don't give up # because Racket's reader already uses # for various stuff. For instance, you can use #rx"foo(?=bar)" to write compiled regexps. Now, if we were writing a reader in Arc, then we'd need to decide whether to use # or not... which I guess we'd have to do anyways, if we were going to unreserve |

I think using #s is fine, except then I'd have to write #s"new " which is even worse than |new | In that case we might as well remove the distinction between strings and symbols...

---

"... but I also just don't see the point of mutating strings."

I think it makes sense to have mutable strings if you see them as a list of characters. But Arc doesn't treat them as a list of characters... so they're this weird data type that's sorta in between symbols and lists...

If Arc treated them as a list of characters, then mutability makes sense, and then we'd have to use `iso` rather than `is`, which also makes sense. But given the way Arc treats strings right now, I think it's better to see them as a special subtype (supertype?) of symbols, in which case I agree that mutability doesn't make sense.

---

"Yeah, I wouldn't suggest doing symbol=string and string=list at the same time."

But... but my beautiful, crazy, and absurd plans! How can you dismiss them so easily?! :P

---

"...since that makes them more confusing to use as hash table keys."

Why? We can already use mutable lists as hash table keys...

-----

1 point by rocketnia 5466 days ago | link

"No, you don't give up # because Racket's reader already uses # for various stuff."

Just because the cost is paid once rather than once for each feature doesn't mean it isn't a cost. If we didn't use # for anything else, we could use it in symbols too. (Penknife allows # in symbols, for instance.)

If we take Racket as a starting point, then # is a heavily overloaded escape character and pretty hard to get rid of. How about changing it to \? :-p Then characters would be written not as #\a but as \\a --or maybe \c"a", if we insist not to use \ for anything but escaping.

---

"Why? We can already use mutable lists as hash table keys..."

Are you saying that makes sense? XD

Here's a http://tryarc.org/ session:

  arc> (= foo (tabl­e))
  #hash()
  arc> (= bar list.­2)
  (2)
  arc> (= foo.b­ar 'woo)­
  woo
  arc> foo
  #hash(((2 . nil) . woo))
  arc> (= bar.0­ 3)
  3
  arc> foo.bar
  nil
  arc> (each (k v) foo prn.v­)
  woo
  #hash(((3 . nil) . woo))
  arc> (each (k v) foo (prn foo.k­))
  nil
  #hash(((3 . nil) . woo))
  arc> (= (foo list.­2) 'boo)­
  boo
  arc> (= bar.0­ 2)
  2
  arc> (each (k v) foo prn.v­)
  boo
  woo
  #hash(((2 . nil) . woo) ((2 . nil) . boo))
  arc> keys.foo
  ((2) (2))
  arc> (each k keys.­foo (prn foo.k­))
  woo
  woo
  nil
This behavior seems to indicate that the table saves the hash of a key when it's entered and then doesn't update that hash when the key is mutated, and that it (probably) stores any keys with equal hashes so that they're checked for full equality in the order they were put in. However, the Racket docs just call the behavior "unpredictable" (http://docs.racket-lang.org/reference/hashtables.html), and that's just fine for a behavior that isn't here for any API-like reason, just here because it's an easier and more efficient implementation than more paranoid alternatives.

Anyway, I suspect you never meant mutable keys made that much sense, just that they make sense as long as we don't actually mutate them. :-p I'm fine with that, just like I'm fine with treating strings as immutable. (I guess one of the paranoid alternatives is to freeze anything used as a table key.)

---

That said, there's a completely different side to this topic I haven't gotten to: On Jarc, every table key is implicitly converted to a string for lookup purposes. I've brought up the point that it would be more consistent if Jarc simulated Racket 'equal? (which pg-Arc uses), but I don't really believe either of these things is the right thing to do, since they compare tagged values by their implementation content. So for my own purposes, I already consider it unpredictable what happens if I use non-symbol table keys, let alone mutable lists.

-----

1 point by Pauan 5466 days ago | link

"Just because the cost is paid once rather than once for each feature doesn't mean it isn't a cost. If we didn't use # for anything else, we could use it in symbols too. (Penknife allows # in symbols, for instance.)"

I know, which is why I mentioned that we would probably need to write an Arc reader in order to unreserve | And if we did that, we would then also need to decide whether to use # or something else.

---

"If we take Racket as a starting point, then # is a heavily overloaded escape character and pretty hard to get rid of. How about changing it to \? :-p Then characters would be written not as #\a but as \\a --or maybe \c"a", if we insist not to use \ for anything but escaping."

Using \ as an escape does seem better than using # to be honest. If we were to write a reader in Arc (which I support, by the way), I think it'd be interesting to try out \ rather than #

---

"Are you saying that makes sense? XD"

I like it better than Python's "you can only store hashable things in keys" approach. Or JavaScript's insane "all keys are coerced to a string, so all Objects are put into the same key" approach.

---

"Anyway, I suspect you never meant mutable keys made that much sense, just that they make sense as long as we don't actually mutate them. :-p I'm fine with that, just like I'm fine with treating strings as immutable."

Yeah, something like that. I suspect Racket behaves that way for performance reasons, but ideally I think it'd be nice if it did update the hashes, so that mutable keys would behave as expected.

---

"(I guess one of the paranoid alternatives is to freeze anything used as a table key.)"

That's basically Python's approach: only hashable things are allowed as keys in objects.

-----

2 points by rocketnia 5465 days ago | link

"I know, which is why I mentioned[...]"

Yeah, I know. ^_^

---

"I like it better than Python's "you can only store hashable things in keys" approach."

Well... you can only use hashable things as keys in Racket too. (How else would hash tables work?) Almost everything in Racket is hashable, but it's possible to make things that kinda aren't, like this:

  arc> ($:define-­struct foo (dumm­y) #:pro­perty prop:­equal+hash­ (list­ (lamb­da args #t) (lamb­da args (erro­r "Can'­t prima­ry hash this.­")) (lamb­da args (erro­r "Can'­t secon­dary hash this.­"))))
  #<void>
  arc> (= my-ta­ble (tabl­e))
  #hash()
  arc> (= my-fo­o $.mak­e-foo!dumm­y-val)
  #<foo>
  arc> (= my-ta­ble.my-foo­ 2)
  Error: "Can't primary hash this."
This is using the 'equal? hash. I don't know if there's a way to make something in Racket that's unhashable with regard to 'eq? or 'eqv?.

You can get at these hash values directly using 'equal-hash-code and friends. http://docs.racket-lang.org/reference/hashtables.html

-----

1 point by Pauan 5465 days ago | link

"Well... you can only use hashable things as keys in Racket too."

Hm... odd, I remember in Python, that you weren't able to use things like lists (which are mutable) as keys... but I guess I remember wrong because I just tried it and it works. Not sure what the problem was that I had with Python's hash tables...

---

By the way, I feel like hash table keys should only use eq, not equal...

-----

1 point by rocketnia 5464 days ago | link

"By the way, I feel like hash table keys should only use eq, not equal..."

Racket has eq-based tables too those, and I wouldn't want 'equal? for weak table keys. However, if I want to use a list or something as a key, it's likely because I want to look something up using multiple values, in which case 'equal? is useful. (In those cases, the ability to intern something into an immutable data structure 'equal? to it would probably be just as useful....)

-----

1 point by Pauan 5466 days ago | link

By the way, I just realized something... symbols, when evaluated, are basically a variable reference... but strings are self-evaluating. So if strings == symbols... then what should (+ "foo" 1 2 3) do? Should it treat the "foo" as a variable reference, or a literal? Would we then need to use '"foo" instead?

So... because symbols evaluate to variables, and strings are self-evaluating, I don't really see a way to use the same syntax for both of them. If we decide that "foo" is equivalent to 'foo then that means we cannot have variable names with weird stuff in them.

On the other hand, if we decide "foo" is equivalent to foo, then that means we can no longer use string literals without quoting them, which is pretty funky. So any solution we choose will be right half the time.

Thus.. we would need to have a separate syntax for them, like using #s"foo" for symbols, and "foo" for strings...

---

Hm... crazy brainstorming: global symbols that don't refer to anything are self-evaluating. That would solve the problem at the cost of being really crazy and confusing. :P

In any case, if strings == symbols, then "foo" would basically just be a shorthand for '#s"foo" (note the quote)

-----

1 point by rocketnia 5466 days ago | link

"Would we then need to use '"foo" instead?"

That's pretty much what I used for my original example at http://arclanguage.org/item?id=14883. If I thought (quote ...) around strings was a deal breaker, the topic would have never come up. :-p

---

"Hm... crazy brainstorming: global symbols that don't refer to anything are self-evaluating."

Isn't that the same idea as http://arclanguage.org/item?id=13823? Or are you having this be determined at compile time rather than run time? That could be an interesting spin on things.

-----

2 points by Pauan 5466 days ago | link

"Isn't that the same idea as http://arclanguage.org/item?id=13823? Or are you having this be determined at compile time rather than run time? That could be an interesting spin on things."

Yes. To be more specific, it's the same idea as point #3 in that post. But it doesn't matter whether it's done at compile time or runtime. The end result is the same: if you have a string literal "foo" and somebody defines a global variable foo, then suddenly your program's behavior changes drastically. Which is why I called it "really crazy and confusing".

--

So, right now, my opinion is that "foo" should basically mean the same thing as (quote \s"foo") where \s"" is syntax for creating a symbol with odd characters in it. That approach isn't 100% ideal in every circumstance[1], but it should be overall the best in the general case.

There is one question, though: should symbols or strings be the primitive? In other words, should it be (isa "foo" 'sym) or (isa "foo" 'string) ?

Personally, though the term "string" is more familiar, I'm actually leaning toward sym. The word "string" is pretty confusing, when you think about it, but "symbol" is a very reasonable thing to call a sequence of characters.

---

As a side effect of making symbols eq to strings... we would also make this work:

  (coerce 'foo 'cons) -> (\\f \\o \\o)
I'm using \\f to mean the same thing as #\f by the way.

Hm... what if we removed chars from the language? What's the purpose of them, really?

---

P.S. Somewhat related: PHP apparently sometimes treats strings as variable references:

http://stackoverflow.com/questions/1995113/strangest-languag...

---

* [1]: I'd have to write "new " rather than new\ How horrible. :P

-----

2 points by rocketnia 5465 days ago | link

"But it doesn't matter whether it's done at compile time or runtime. The end result is the same: if you have a string literal "foo" and somebody defines a global variable foo, then suddenly your program's behavior changes drastically."

If it's done at compile time, it's a bit better: The program's behavior doesn't change at all if someone defines a global variable 'foo after your code has been loaded.

---

"So, right now, my opinion is that "foo" should basically mean the same thing as (quote \s"foo")..."

My first impression seeing reader syntaxes like \s"foo" is that the reader will recursively read "foo" and then convert the result somehow.

I guess it could read "foo" as (quote foo) and convert that result using 'cadr, lol. :-p

---

"The word "string" is pretty confusing, when you think about it, but "symbol" is a very reasonable thing to call a sequence of characters."

Huh, nice observation. ^_^ I think I've called strings "texts" sometimes, so mayhaps that's another option.

---

"I'm using \\f to mean the same thing as #\f by the way."

I see that as using \ in a non-escaping way. I don't have a problem with using it that way, but I don't have a problem with using it as a delimiter either.

---

"Hm... what if we removed chars from the language? What's the purpose of them, really?"

Would you have a symbol be a sequence of length-one symbols, and have every length-one symbol be its own element? Anyway, I don't have any opinion about this. :-p

---

"P.S. Somewhat related: PHP apparently sometimes treats strings as variable references"

Jarc does the same thing if you call a symbol. I don't really have an opinion about this either.

-----

1 point by Pauan 5465 days ago | link

"Huh, nice observation. ^_^ I think I've called strings "texts" sometimes, so mayhaps that's another option."

Sure, but traditionally Lisp has used the term "symbol", and even languages like Ruby have picked up on it. And there's another thing. Symbols in Lisp are often used as variable names. In that context, the word "text" doesn't make much sense, but the word "symbol" still makes perfect sense. So I still vote for "symbol", even though I think "text" is more reasonable than "string".

---

"Would you have a symbol be a sequence of length-one symbols, and have every length-one symbol be its own element? Anyway, I don't have any opinion about this. :-p"

Yes. :P At least, when coerced to a list. This would let us get rid of two similar-but-not-quite-the-same data types: strings and chars. It annoys me that I have to use (tokens foo #\newline) rather than (tokens foo "\n")

I don't really see much purpose or benefit of having a distinction between chars and strings... Python and JavaScript get by just fine with only strings, for instance.

In addition, I find myself juggling between symbols and strings a lot... converting to a sym when I want Arc to see it as an identifier, and as a string when I want to do things like index into it, or coerce it to a list... or when Arc code requires a string rather than a sym, etc... The more I think about it, the better it seems to unify strings/symbols/characters.

-----

2 points by rocketnia 5464 days ago | link

I thought the point of the term "symbol" was to signify something that was used as a name. I do think it's a tad more evocative to call every string a symbol, but it feels a bit like calling every cons cell a form.

Inasmuch as I have any desire to be traditional, I'll call strings strings. :-p

-----

1 point by Pauan 5472 days ago | link | parent | on: Syntax.for(lisp)

I agree overall, but... I will note that object orientation is possible, for instance with my "object.arc" library[1]. However, I don't use the "." syntax for that either... for instance, this in JavaScript:

  foo.bar(qux);
Would be this, with my library:

  (foo<-bar qux)
However, it may be cool to be able to write "foo.bar(qux)" with my library instead. I've also considered a pretty radical idea, having every function dispatch to a method on an object. So this:

  (car foo)
Would translate to this, automatically:

  (foo<-car)
In any case, I agree that with functional style, I prefer Arc's syntax. But assuming somebody were to write/use an OOP library for Arc, I can see why they would prefer a more traditional syntax.

I think, ideally, Arc should allow you to change the syntax, on a file-by-file (expression-by-expression?) basis. Then the default could be what it is right now, but still allow people to write with whatever syntax they want. Arc isn't there yet, but I think that's a nice ideal to strive for.

---

P.S. Somewhat related, is the concept of "sweet expressions": http://www.dwheeler.com/readable/

With sweet expressions, you can write "foo(bar)" rather than "(foo bar)", but it still allows you to use "(foo bar)" when you want to. In other words, it lets you mix-and-match Lisp syntax and more traditional syntax, even within the same file. So you can use whichever one happens to be most readable at the time.

---

* [1]: https://github.com/Pauan/ar/blob/lib/object.arc

-----

1 point by Pauan 5473 days ago | link | parent | on: Pipes and s-expressions

I agree.

-----

3 points by Pauan 5474 days ago | link | parent | on: On Modules

Option 3: first-class namespaces, which is the approach that Python uses (albeit it doesn't have macros).

So for instance:

  ; file "foo.arc"
  (def helper (x)
    (+ 5 x))

  (mac something ()
    `(helper 10))


  ; file "bar.arc"
  (import foo)

  (foo!something) -> 15

  (w/eval foo
    (something)) -> 15

  (something) -> error: undefined variable something

  (= something foo!something)

  (something) -> 15

  (w/eval namespace
    (something)) -> error: undefined variable helper
I did some work on this with my previous "import.arc", and I just added in initial support for macros. Because namespaces are first-class objects, they can contain all sorts of information about the mapping between names and values. There's also some nifty stuff you can do with them as well, like namespace inheritance.

The primary benefit of namespace inheritance is speed: rather than recompiling the entire ar compiler every time, you instead compile it once, and then create light-weight namespaces that inherit from it.

You can think of it like the difference between storing copies of two files, and storing the diff of two files. Obviously storing the diff will be much shorter in most cases, because there will be many parts that are the same between the two.

So rather than creating an entire fresh new namespace every time, you just store the differences, which allows namespaces to be created super-fast and also consume less memory.

I would like to note that all of this already works with "import.arc"... it's not just theory, it works right now, and you can use it right now in your own code. It's not perfect, of course, but at least it works.

Also, I'll note that my solution for macros with regard to namespaces is to basically evaluate the macro at runtime. This works, but is obviously less efficient than I'd like. I think it's possible to optimize it so it only needs to do the macro expansion one time.

---

By the way, I would like to point out that "import.arc" does not create new runtimes... runtimes are a superset of namespaces. You can think of them like namespaces + other features. "import.arc" focuses solely on namespaces.

Why? Well, ar already has support for runtimes. I see runtimes as being useful for creating new languages and having them run side-by-side with other languages. Like, say, Arc/3.1 and Arubic. Or Arc/3.1 and Perl. Or whatever.

But I see a difference between runtimes and namespaces. Sometimes you want namespaces within a language. Using a full-blown runtime for that is overkill. You just want a mapping between names/values, and that's what "import.arc" gives you. If you want to create a new language, or a language variant, then I would suggest you use ar's already-existing support for runtimes.

---

Also, I still need to solve one particular problem with namespace inheritance. One solution I've been thinking about is making all global variables dynamic, but I'll need to play around with that to see if it'll work or not.

-----

1 point by aw 5474 days ago | link

Ah, so when a macro gets evaluated, it gets evaluated in its namespace? That's clever!

-----

1 point by Pauan 5474 days ago | link

Yes. At runtime. Even ignoring the inefficiency of expanding macros at runtime, there's one other thing that concerns me, and that's anaphoric macros.

If somebody writes a macro like "aif" or "aand" or whatever, you want the variable "it" to refer to the caller's namespace, but all the other variables to refer to the definer's namespace...

I think this is a solvable problem, but I think it'll require more complexity to solve.

By the way, I think I can add in a system where you can selectively choose which variables should be expanded in your namespace, and which ones shouldn't. Something like this:

  (import foo)

  (w/names (it)
    (foo!something))
This says that the variable "it" should be expanded into your namespace, and all other variables should be expanded in foo's namespace.

Interestingly enough, if I implemented such a system, you could then overwrite certain variables in a macro's body:

  (def helper (x)
    (+ x 50))

  (foo!something) -> 15 ; uses foo's version of helper

  (w/names (helper) ; uses my version of helper
    (foo!something)) -> 60

-----

1 point by Pauan 5474 days ago | link

Actually, there's another thing that also concerns me... Consider this macro:

  (def foo args
    (apply prn args))

  (mac bar (x . args)
    `(foo (string ,x) ,@args))
If you call bar, you want the variables "x" and "args" to be expanded in your namespace, but everything else to be expanded in bar's namespace.

-----

1 point by aw 5474 days ago | link

Have you published import.arc somewhere?

-----

1 point by Pauan 5474 days ago | link

Yes. It's in the "lib" branch of my fork:

https://github.com/Pauan/ar/blob/lib/import.arc

It's a bit messy right now, though.

---

Also, `import` is still using `load`, rather than `use`. So you'd use something like this:

  (import foo "../path/to/foo.arc")
Rather than this:

  (import foo)
This has both advantages and disadvantages. What I'd like to do is have (import foo) behave like (use foo), but with namespace isolation. And then we could have an (import-as foo "../path/to/foo.arc") for more precise control.

---

I'd also like to note that "import.arc" is still basically alpha-state, so I make absolutely no guarantees about whether it'll work or not. My suggestion would be to try it, and if something breaks, tell me about it so I can try to fix it.

Basically, it's a prototype that attempts to demonstrate that the concept is both possible and feasible.

-----

1 point by Pauan 5479 days ago | link | parent | on: Pauan's racket discovery: procedure-rename

No offense, akkartik, but does this really need an entire topic for it? I just looked through the docs and found a useful function. It's not even a particularly complicated function: it just returns a function with a specific name. I do appreciate the attention, but if so, shouldn't we also make a topic for, say, "make-derived-parameter"? Or perhaps "string->uninterned-symbol"?

-----

1 point by akkartik 5479 days ago | link

It seemed like something that people here would like to know about. I don't know if everyone reads on convore.

We've started posts to respond to comments before, just because the server deletes the reply button for old threads. I've started thinking of /newest and /newcomments interchangeably in such a small community, where sometimes a week passes without anything new. But I can change if others agree with you.

If you post about make-derived-parameter (and the slightest extra context about what it can do for arc) I'd be all ears. I have trouble making out shapes in racket's documentation thicket. The fact that pg/rtm don't seem aware of procedure-rename either suggests I'm not alone.

-----

1 point by aw 5479 days ago | link

I think your discovery is important enough to warrant mentioning on the forum, since it is A) useful, and B) something that most people didn't know about. (At least, I knew about string->uninterned-symbol, but not procedure-rename).

-----

1 point by Pauan 5483 days ago | link | parent | on: Pipes and s-expressions

Yes! I've written shell scripts in Arc, and I've noticed that the Unix concept of pipes (and especially the syntax for them) is very elegant and concise.

But why not just make it a binary operator, like in Unix?

  x | y | z
  (z (x y))
I'll note that this would solve a problem I've been having... In particular, notice this pattern:

  (w/foo 1 (w/bar 2 (qux)))
The above could be written as this, instead:

  (qux) | w/bar 2 | w/foo 1
Hm... perhaps the bars should be reversed, so it would be like this:

  w/foo 1 | w/bar 2 | (qux)
I've had some situations where I kept wishing I had some syntax to make them shorter, but I wasn't sure exactly what kind of syntax would help...

-----

1 point by akkartik 5482 days ago | link

..why not just make it a binary operator..?

Hmm, you mean an infix operator, right? I'm not sure how to fit an infix operator into an otherwise prefix language. I'm sure lots of questions arise. Operator precedence, where the right-hand arg terminates. If there's a simple model that answers those questions well that would be great.

-----

1 point by Pauan 5482 days ago | link

Yes. One potential solution is the curly infix system described here (scroll down a bit):

http://www.dwheeler.com/readable/sweet-expressions.html

Though that does add two extra characters:

  {x | y | z}

-----

1 point by akkartik 5482 days ago | link

Ah, I keep losing that page, thanks!

But for this particular case I'd rather just add an extra '|' and make it all prefix.

-----


Perhaps you would be interested in Jarc[1] or Rainbow[2], both of which are Arc implementations that run on the JVM.

You can find a list of other Arc implementations here:

http://sites.google.com/site/arclanguagewiki/home

---

* [1]: http://sourceforge.net/projects/jarc/files/

* [2]: https://github.com/conanite/rainbow

-----

1 point by Pauan 5500 days ago | link | parent | on: Arc2js, an Arc to JavaScript compiler

Ah, nice.

-----

More