Arc Forumnew | comments | leaders | submitlogin
New version
57 points by pg 6158 days ago | 84 comments
You can find it at http://ycombinator.com/arc/arc1.tar

Please let me know if there are any new glitches.

There are a bunch of changes, many of them fixing bugs reported here. The most dramatic change is probably the ability to use x.y and x!y as abbreviations for (x y) and (x 'y) respectively.



10 points by jgrahamc 6158 days ago | link

Cool.

Am I right in saying that write always flushes stdout instead of the port it's passed?

(xdef 'write (lambda args (if (pair? args) (write (ac-denil (car args)) (if (pair? (cdr args)) (cadr args) (current-output-port)))) (flush-output) 'nil))

-----

4 points by offby1 6158 days ago | link

I do believe you're right; I think I fixed that in the ac.scm available at git://git.nex-3.com/arc-wiki.git

-----

8 points by pg 6158 days ago | link

Oops, will fix.

-----

13 points by drcode 6157 days ago | link

I just realized the clever visual pun:

"!" looks like "." and "'" put together!

(I would still favor replacing x!y with x.'y though... I couldn't find a single use for x!y in any of the arc code I've written so far...)

-----

11 points by EliAndrewC 6157 days ago | link

I like that "subseq" was renamed to "cut" and that it now takes negative indices.

However, I wish we could say (x 1 -1) instead of (cut x 1 -1). And since x.0.0 expands to (x 0 0) then that would let us say x.1.-1 which is what languages such as Python and Ruby already allow.

I hope that this is coming; I image that Arc's creators don't want to introduce too many changes all at once, so maybe they'll add this after they see how the x.y syntax works out.

-----

8 points by sjs 6157 days ago | link

I would prefer it if (cut "abcde" 1 -1) returned "bcd" rather than "bcde". Other than that I like the new cut.

-----

8 points by pg 6157 days ago | link

Hmm, yes, so would I. I should fix that. I just did what Emmett suggested, which must have been based on Ruby, but it doesn't actually seem like a good idea.

-----

5 points by pg 6157 days ago | link

Fixed. http://arclanguage.org/item?id=2304

-----

4 points by nex3 6157 days ago | link

Given this, I've changed it to 0-based reverse indexing in the Anarki.

-----

3 points by jules 6157 days ago | link

In Ruby you use Ranges for this.

    (1..4).to_a => [1,2,3,4]
    (1...4).to_a => [1,2,3]
str[a..b] is a substring from a to b, inclusive.

str[a...b] is a substring from a to b, exclusive.

With negative indices:

    str[a..-b] == str[a..str.length-b]
    "abcde"[1..-1] == "abcde"[1..5-1] == "abcde"[1..4] == "bcde"

    str[a...-b] == str[a...str.length-b]
    "abcde"[1...-1] == "bcd"

-----

1 point by carpal 6157 days ago | link

How else would you specify "the end of the string"? -1 seems natural for me. Anything else (0?) makes it kind of foggy.

-----

5 points by nex3 6157 days ago | link

"End of string" is specified by not passing a fourth parameter:

  > (cut "abcde" 1)
  "bcde"
See http://arclanguage.org/item?id=2267.

-----

2 points by maxwell 6156 days ago | link

-0

-----

2 points by nex3 6157 days ago | link

Agreed. Ruby does it the other way ("abcde"[1..-1] is "bcd"), but that's only because there's no other way to specify "until the end." But that's the default in Arc; the following are equivalent right now:

  (cut "abcde" 1 -1)
  (cut "abcde" 1)

-----

3 points by lsb 6157 days ago | link

Nope, Ruby has -1 at the end:

    $ irb
    >> "abcde"[1..-1]
    => "bcde"
    >>

-----

4 points by nex3 6157 days ago | link

Oh, right. That's what I meant.

So, to clarify: I think arc should not do it Ruby-style, but rather have

  arc> (cut "abcde" 1 -1)
  "bcd"

-----

2 points by mec 6157 days ago | link

How would you then decide 0 0?

  arc> (cut "abcde" 0 0)
  "a"
  arc> (cut "abcde" 0 0)
  "abcde"
-1 should deffinitly refer to the last elemental or I don't see a way to get it.

-----

3 points by nex3 6157 days ago | link

(cut s 0 0) should return the empty string, just like (cut s 1 1) and (cut s 42 42). Which it does in either implementation.

-----

2 points by vincenz 6157 days ago | link

Then you would need -0 to get the full string. You're not making sense.

How do you propose to get "bcde" from "abcde"?

Either you need -0, or your final 0 is ambiguous.

-----

3 points by nex3 6157 days ago | link

No you don't - the full string is the default.

  > (cut "abcde" 1)
  "bcde"

-----

3 points by tokipin 6157 days ago | link

i was thinking that too, but how would you do it dynamically (eg with variables) ?

  (cut "abcde" begin end)
what would i need to put in end to get the full string? nil?

-----

3 points by sjs 6157 days ago | link

Both nil and (len str) work. I see both sides of the argument as counting from -1 eliminates the 0 corner case.

I like indices that are intuitive with literal numbers. Counting from 0 at one end and from 1 at the other is jarring. When -1 points to the end of string rather than before the last char (cut str 0 (- (len str))) returns the first char instead of the empty string.

With -1 -> before last char:

  (def chop ((o str "abcdef"))
    (pr "Chop how many chars off the end of \"" str "\"? ")
    (= n (coerce (cut (readline) 1) 'int)) ; bug in readline prepends #\newline
    (prn "Chopped: \"" (if (is n 0) str (cut str 0 (- n))) "\"")) ; handle corner case
With -1 -> end of string:

  (def chop ((o str "abcdef"))
    (pr "Chop how many chars off the end of \"" str "\"? ")
    (= n (coerce (cut (readline) 1) 'int)) ; bug in readline prepends #\newline
    (prn "Chopped: \"" (cut str 0 (- -1 n)) "\"")) ; no corner case, but there's this -1 there
I probably made a stronger argument for -1 pointing to the end of string as it leads to shorter code.

-----

2 points by nex3 6157 days ago | link

If you absolutely need to do that, you can just use (len str).

-----

3 points by akkartik 6157 days ago | link

Yup. Which is how python does it.

-----

2 points by jules 6157 days ago | link

    $ irb
    >> "abcde"[1...-1]
    => "bcd"

-----

5 points by mdemare 6157 days ago | link

I've started a new thread with cut compared in Ruby and Arc: http://arclanguage.org/item?id=2257

-----

2 points by nex3 6157 days ago | link

Agreed. On a related note, I also wish the first parameter could be negative as well.

-----

3 points by chandler 6157 days ago | link

What you're proposing is an alternate non-parenthetical syntax (i.e. x.y.z => (x y z)). Careful! Down this road lies ruin.

-----

4 points by EliAndrewC 6157 days ago | link

While I agree that this shouldn't be abused, I'm not actually proposing this syntax; Arc already lets you say cut.x.1.3 as an alternative to (cut x 1 3).

I suspect that the only time I'd ever want to chain together several different things with . is when I'm doing list slices. Which is why I'd like the x.1.3 syntax to work, since in my opinion cut.x.1.3 is a lot uglier, perhaps enough that I'd rather not do it.

-----

5 points by drcode 6158 days ago | link

  arc> +.3.3
  6

  arc> isa!x!sym
  t

  arc> cdr!(1 2 3)
  Error: "Can't take cdr of #<eof>"

  arc> (= x '(1 2 3))
  (1 2 3)
  arc> cdr.cdr.x
  Error: "procedure ...rcode/arc/ac.scm:561:11: expects 1 argument, given 2: #<procedure:...rcode/arc/ac.scm:561:11> (1 2 3 . nil)"
This one has me stumped:

  arc> (def foo (x) [+ 10 _])
  #<procedure: foo>
  arc> foo.3
  #<procedure>
  arc> (+:foo.3 5)
  15

-----

7 points by pg 6158 days ago | link

! and . are for separating symbols and integers.

x.y.z means (x y z)

-----

3 points by eds 6157 days ago | link

Playing around with combining ":" and "."....

  arc> (= x [+ 10 _])
  #<procedure: x>
  arc> (prn:prn.x 5)
  #<procedure: x>
  15
  15
  arc> (prn:prn.x 5)
  #<procedure: x>
  15
  15
  arc> (prn (prn.x 5))
  #<procedure: x>
  15
  15
  arc> (prn ((prn x) 5))
  #<procedure: x>
  15
  15
Is this actually the way the first expression is being expanded? I can think of situations where I would want (foo:bar.arg) to be expanded to (foo (bar arg)) not (foo ((bar arg))). Just a thought.

-----

2 points by sjs 6157 days ago | link

I think it makes sense.

  arc> (def add (x) [+ x _])
  #<procedure: add>
  arc> (map [prn:add.40:idfn _] (range 1 5))
  41
  42
  43
  44
  45
  (41 42 43 44 45)

-----

5 points by kens 6158 days ago | link

I'd expect that "abc".1 would return #\b?

-----

5 points by pg 6157 days ago | link

No, it would read as two separate things, a string and the number .1; symbol-syntax has lower "precedence" than Lisp read.

-----

4 points by sjs 6157 days ago | link

  arc> (= s "abc")
  "abc"
  arc> s.1
  #\b

-----

6 points by oconnor0 6158 days ago | link

Is there a reason you limit ! and . to work only for symbols and integers?

-----

7 points by pg 6157 days ago | link

The plan with intrasymbol syntax is (a) not to break traditional Lisp read and (b) to expand in place. If you have those two constraints, instead of just saying "ok, put any syntax anywhere," you can introduce syntax into Lisp without getting too unLispy.

-----

1 point by oconnor0 6156 days ago | link

Right. Maybe it's the traditional Lisp read that's the main factor here because it seems that you could expand in place without issue given even arbitrary expressions.

If a.b expands to (a b) then (f v w).(g x y) would just expand to ((f x y) (g x y)). At first glance, that definitely appears to be a cool way to grab just one of the results from a function return (ala (f x y).2).

Hmm, on the down side, you could have statements like (or worse):

    (bst-find tree 45 f<).(if (< 10 42) (/ 4 3)
                              (> 4 2)   x
                                        'r)
That being said, having to change read to get this to work may affect far too much and make arc too ugly.

-----

3 points by treef 6157 days ago | link

i think the code will look rather harry if they are allowed to be every where.

-----

8 points by nex3 6158 days ago | link

I've added this as branch "official" of the arc wiki. I've also tried to merge it into the master branch. I resolved everything I knew how, but there might be some regressions and references to renamed/no-longer-existent functions hanging around.

-----

6 points by ryantmulligan 6157 days ago | link

it would be nice if we made specs to test the language, a la Rubinius, while the language is still small. Then, we could say with greater confidence of the merge.

-----

5 points by jgrahamc 6158 days ago | link

Also, it would be really nice to have the ability to connect to a remote TCP port. Something like:

(xdef 'connect-socket (lambda (host port) (let-values ([(in out) (tcp-connect host port)]) (list in out))))

-----

7 points by pg 6157 days ago | link

I just replaced arc1.tar with a new version in which (cut "foobar" 1 -1) -> "ooba". Since that was the only change I just overwrote the old file.

-----

4 points by nex3 6157 days ago | link

I've pushed this change to the official branch of the Anarki.

-----

2 points by duaneb 6157 days ago | link

...so that means that (cut "foobar" 0 0) is "foobar"? How does that make sense?

I think that the -1 ending the string makes more sense when you take the zero into account.

-----

5 points by nex3 6157 days ago | link

(cut "foobar" 0 0) is "", just like (cut "foobar" 1 1) and (cut "foobar" 42 42). 0 isn't a negative number.

-----

5 points by andreyf 6157 days ago | link

As pointed out above, (cut "foobar" 0 0) is "", and (cut "foobar" 1) is "oobar".

-----

3 points by parenthesis 6157 days ago | link

The . ! syntax is great.

A possible problem is that I can see myself wanting to use this syntax a lot for accessing hash tables with symbols as keys. But ! is a lot more annoying to type than . is.

My alternative suggestion (which I'm sure has worse problems of its own) would be

  x.y  ->  (x 'y) if y is a symbol, (x y) otherwise

  x,y  ->  (x y)   (by analogy with , inside backquote)

  x!y  ->  (x 'y)  (if there should ever be a need to quote a non-symbol?)
Edit: Also in favour of my proposal, ! looks too much like a letter l:

  a!ex
Whereas

  a.ex
is very clear.

-----

3 points by EliAndrewC 6157 days ago | link

. and , are not very visually distinctive. It'd be like having (x 0) and (x O) both be commonly used.

-----

5 points by mattjones 6157 days ago | link

The . and ! syntax is really handy.

I noticed chaining doesn't work for .:

    arc> (= l '(1 2 (3 4) 5))
    (1 2 (3 4) 5)
    arc> l.2
    (3 4)
    arc> l.2.1
    (3 4)
rather than 4. Another thought ... could ranges be expressed a la Ruby?

    arc> (= l '(1 2 3 4 5))
    (1 2 3 4 5)
    arc> l.1..4
    (2 3 4 5)

-----

5 points by sjs 6157 days ago | link

Multiple dots pass multiple params to the initial function. To chain you have to group w/ parens.

  arc> (= l '(1 2 (3 4) 5))
  (1 2 (3 4) 5)
  arc> l.2.1
  (3 4)
  arc> (l.2 1)
  4
That 2nd last one translates to (l 2 1), which as you found acts like (l 2).

-----

3 points by mattjones 6157 days ago | link

Yep, thanks. It would be cool if there were an abbreviation for that, since it's fairly common. Eg l.2%1 (% randomly chosen) => ((l 2) 1). Some may say that goes too far toward a parentheses alternative for all sorts of things, but on the other hand data structure access is one of the clumsier parts of Lisp.

The present semantics of . make sense though.

-----

2 points by andreyf 6157 days ago | link

Maybe 'l' is not the best letter for that variable?

-----

7 points by kostas 6158 days ago | link

PG,

Grepping the source, the x.y and x!y syntax doesn't seem to be used.

Have you tried them out on the news.yc code? What's your initial feel in terms of code compression?

-----

6 points by pg 6158 days ago | link

I've been trying this syntax on example programs for several weeks. Maybe months, actually. It doesn't yield startling results in compression if you count x.y as 3 nodes, but it does make programs easier to read, particularly when you use it for structure access.

-----

9 points by curi 6157 days ago | link

why not change x!y to x.'y ? seems a bit easier to remember, saves ! for something else. dunno if there's a parsing problem with it.

-----

7 points by pg 6157 days ago | link

Hmm, never thought of that. I'll consider it.

-----

3 points by mattjones 6157 days ago | link

What if x.y!z expanded to ((x y) z)? Then if x were '(1 2 (3 4) 5), x.2!1 would give you 4. If (x 1 3) did work like cut, then you could do x.1.3!1!1, which would also give 4 in this case.

-----

2 points by kens 6157 days ago | link

pipe-from is (still?) broken on Windows since it uses /dev/urandom. Maybe use make-temporary-file instead? (pipe-from is not really a pipe; it directs command output into a file, and then reads from the file; having a real pipe would be nice. Also, it does a rm -f, which isn't too good on Windows either.)

-----

10 points by kostas 6158 days ago | link

Still recommending mzscheme 352?

-----

6 points by pg 6157 days ago | link

Yes. It doesn't make any difference.

-----

1 point by markokocic 6156 days ago | link

It does to new users migrating from mzscheme. Not everyone is going to downgrade mzscheme to 20 revisions old package just to try out new lisp dialect.

Bringing it up to date would probably increase its adoption.

-----

5 points by absz 6156 days ago | link

I think he meant that updating Arc didn't make any difference to the requirements, not that using an old mzscheme doesn't make any difference, which it certainly does. I wouldn't be using Arc if there hadn't been a patch to get it working on newer mzschemes; the git "wiki" (http://git.nex-3.com/arc-wiki.git) works on said mzschemes right now. It may not be official, but it might help scratch your itch.

-----

7 points by koder 6157 days ago | link

just want to ask why scheme? why not c-lisp?

(i'm new here)

-----

12 points by pg 6157 days ago | link

Being a Lisp1 and having continuations made it a more natural fit.

-----

4 points by Zak 6157 days ago | link

What is c-lisp? Do you mean GNU CLISP, an implementation of the Common Lisp language? Do you mean Common Lisp in general? I think the main reason for using Scheme as a host instead of CL is that Arc is more similar to Scheme than CL.

-----

4 points by koder 6157 days ago | link

hi zak, i meant common lisp (CL), i thought Paul more inrested in CL and he didn't like to do his work in Scheme!

-----

1 point by connellybarnes 6150 days ago | link

I like MATLAB syntax best. 1:5 builds a range. 1: should build the infinite range, but MATLAB is crippled and only lets you do x(1:end). In Lisp syntax, (x 1:) would be item 1, 2, etc of x, (x lo:hi) would be lo, ..., hi-1. I'd also find this convenient because I often need to loop from 0 to infinity and 1 to infinity. Although Python's syntax of using negative numbers to index from the end of the list is far more convenient than 'end' in MATLAB, and it goes without saying that MATLAB's 1-based indexing is Satanic.

Using lots of syntax (e.g. Python's range(a, b)) for range construction is completely unacceptable, and using different syntax to index into an array and construct a range is annoying, due to violating fairly basic notions of beauty in mathematics (Equal things can be replaced by each other; Use one abstract syntax to cover lots of ideas, instead of lots of syntax to cover few ideas). Also, if one leaves out sane floating-point range construction methods, then they get added over and over again in 3rd party libraries (e.g. numpy.arange in Python).

-----

8 points by godtvisken 6157 days ago | link

Will the tutorial be updated?

-----

6 points by pg 6157 days ago | link

I already updated it in the sense of removing incompatibilities. Will intro the new syntax soon.

-----

2 points by cooldude127 6156 days ago | link

also, the install instructions probably should reference the new version as well.

-----

4 points by bkz 6157 days ago | link

Why not implement full syntax for array access ala Python (x[rng_min:rng_max])?

Is Arc turning into Perl 6 implemented using the Lisp axioms?

If code compression in terms of tokens is the most important design goal why not go for something like J?

-----

4 points by vdm 6157 days ago | link

Please link up "J" unless you just expect people to know what it is without guesswork.

-----

3 points by helium 6157 days ago | link

It's a language similar to APL. Finding out what J is is as simple as searching for j programming language in e.g. google. Results are e.g. http://en.wikipedia.org/wiki/J_programming_language

-----

1 point by rapp 6157 days ago | link

Better yet, the addition of the language features, brevity, and power of K [ http://www.kuro5hin.org/story/2002/11/14/22741/791 ]

-----

2 points by ecmanaut 6154 days ago | link

The mkdir -f in arc.arc's ensure-dir does not work on MacOS X, where the syntax is mkdir -p -- so the (asv) example in the tutorial fails.

-----

3 points by pg 6154 days ago | link

Anyone know what I should use to work in the maximum number of OSes?

-----

3 points by ecmanaut 6153 days ago | link

Any specific reason not to use (make-directory) instead of (system "mkdir ...") and let scheme handle the portability? http://download.plt-scheme.org/doc/372/html/mzscheme/mzschem...

-----

1 point by CatDancer 6153 days ago | link

Rather bizarrely, on my Linux system at least, make-directory is creating directories with the sticky bit set... and I didn't see anywhere in the MzScheme's manual a way to set the umask. Perhaps someone else will have better luck.

If this can be fixed, the make-directory* function in the MzScheme file.ss library will usefully create intervening directories, like mkdir -p does.

-----

3 points by elibarzilay 6151 days ago | link

That was fixed in version 371.

-----

1 point by CatDancer 6153 days ago | link

mkdir -p

-----

1 point by xscott 6155 days ago | link

When I look at x.y, I see attribute/method access as in many other languages, so it seems to me that the Arc analog should be (x 'y). Maybe this is a worthwhile abbreviation for pulling out a subitem. For function application though, I don't see why you would want a shortcut for (f x) when f.x or f!x isn't really much shorter.

-----

1 point by araujo 6157 days ago | link

Does this probably should work? list!(1 2 3)

-----