Arc Forumnew | comments | leaders | submit | Jesin's commentslogin
5 points by Jesin 6632 days ago | link | parent | on: Does Arc need modules? Maybe not.

He seems not to be saying we shouldn't have modules, but instead that we shouldn't use this kind of module.

-----


I think that if a:b.c means anything, it should be (a (b c)). I can understand that : is normally right-associative, i.e. a:b:c:d means (compose a (compose b (compose c d))) rather than (compose (compose (compose a b) c) d). However, it's really counterintuitive that a:b.c currently means (compose a (b c)) rather than ((compose a b) c).

While I agree wholeheartedly that "Should the programmer be allowed to...?" should be answered "yes" as much as possible, the a.b syntax confuses me. While it's totally understandable that a.b means (a b), it's weird that a.b.c means (a b c).

I like the function composition syntax a lot. (a:b foo) is easier to type than (a (b foo)), and the benefits scale linearly; compare (a:b:c:d foo) with (a (b (c (d foo)))), and (baz a:b:c:d) with (baz (fn args (a (b (c (apply d args)))))).

I fail to see the benefits of the function application syntax. Typing a.b is hardly any easier to type than (a b), and is also harder to understand instantly upon reading. As you add more arguments, the bad gets worse and the good doesn't get better. The gains in brevity and typing speed in writing a.b.c.d rather than (a b c d) are no better than those of writing a.b rather than (a b). However, once you start using the syntax for more than one argument, you have to remember that a.b.c.d means (a b c d), rather than (((a b) c) d) or (a (b (c d))). It gets worse when you try to mix them, as in a:b.c, a.b:c, or a:b.c:d (what would this last one even mean?).

Some proposals: Drop the a.b syntax altogether Do not allow mixing of . and : Allow only one . per thing At the very least, drop a!b and let us just use a.'b; it's easier to understand and no harder to type.

I am not comfortable with disallowing anything, partly due to bad experiences with languages that do so. The other syntax at least makes sense (things like [ _ ], :, and the usual Lisp stuff like ' ` , ,@). I don't see the point of a.b, why not drop it entirely?

-----

1 point by Jesin 6634 days ago | link | parent | on: Top 10 differences between Scheme and Arc

Arc lists are terminated with nil, rather than '().

Wrong.

arc> (is 1 2)

nil

arc> (if '() 'true 'false)

false

arc> '()

nil

arc> (is '() nil)

t

Whereas, in Scheme, (display (if '() "true" "false)) outputs true, (display (= 1 2)) outputs #f, and (display (= #f '()) outputs #f.

-----

1 point by eds 6634 days ago | link

From the arc side of things it may look like () and nil are the same, but on the scheme side of things, nil is a symbol, not at all related to the empty list ().

And as a matter of fact, arc lists are indeed terminated with the symbol nil.

  > mzscheme -m -f as.scm
  Use (quit) to quit, (tl) to return here after an interrupt.
  arc> (cdr '(1))
  nil

  > mzscheme
  Welcome to MzScheme version 352, Copyright (c) 2004-2006 PLT Scheme Inc.
  > (cdr '(1))
  ()
and also

  arc> '(1 . nil)
  (1)
  arc> '(1 . ())
  (1)

  > '(1 . nil)
  (1 . nil)
  > '(1 . ())
  (1)
the second arc example '(1 . ()) evaluates to (1) but still results in a nil terminated list

  arc> (cdr '(1 . ()))
  nil
The fact that nil and () happen to be equivalent in arc has nothing to do with whether lists are nil or () terminated.

And I could have sworn I had gotten an error once that showed that an arc list had gotten into scheme somehow, but I can't remember exactly what I did to cause the error right now. I think it was something like:

  Error: some function expected a proper list but got '(3 + 4 . nil) instead.

-----

1 point by nlavine 6633 days ago | link

On the contrary, the question of how a particular implementation represents with arc lists has nothing to do with what arc lists are.

In fact, you could make ac.scm more efficient by doing a (define nil '()), eliminating all the denil stuff, and then changing the print routines, if you cared to.

-----

3 points by kens 6633 days ago | link

Is ac-niltree/ac-denil a constant overhead, or does it make some O(1) operations into O(n) operations? Hopefully the nil/denil traverses the whole list only when you're already traversing the whole list. But I haven't been able to convince myself that's always the case. This is on my list of things to investigate, but has anyone already figured this out?

-----

1 point by eds 6633 days ago | link

I'm not completely sure, but I think this is a compile-time overhead. So when you type directly into the toplevel, its a O(n) overhead, but when you execute a function defined in arc, executing the function itself should be less additional overhead because it was compiled to a scheme function in the original def.

  ; translate fn directly into a lambda if it has ordinary
  ; parameters, otherwise use a rest parameter and parse it.
  (define (ac-fn args body env)
    ; ...

-----

2 points by nostrademons 6633 days ago | link

Have to watch out for corner cases - Arc's usage of 'nil as the list terminator is exposed in several places within the language itself. For example `(is (coerce "nil" 'sym) (cdr nil))` is true under the existing implementation, yet would be false if you just (defined nil '()). You'd need to patch `is`, `coerce`, and possibly a bunch of other primitives to preserve the existing behavior.

-----

1 point by almkglor 6633 days ago | link

Which exposes the problem of "the code is the spec". If there was a prose spec, pg could have just said that such stuff was undefined and we wouldn't care that such things break.

-----

3 points by akkartik 6633 days ago | link

If stuff doesn't work right, having the spec say it's supposed to not work right doesn't help at all.

Prose specs came into being to help multiple implementations interoperate (somewhat) when implemented in low level languages. I don't see the need when you have just one pretty concise and declarative implementation.

-----

1 point by eds 6633 days ago | link

The question of how a particular implementation represents with arc lists has nothing to do with what arc lists are.

The code is the spec.

The fact remains that in arc when you type '(a b c) you get '(a . (b . (c . nil))) and in scheme you get '(a . (b . (c . ()))).

You could make ac.scm more efficient by doing a (define nil '())

There is a difference between nil being the empty list and nil evaluating to the empty list.

One problem with (define nil '()) is that then 'nil returns the symbol nil rather than the empty list ().

I am not convinced that (define nil '()) would greatly increase efficiency, because most of that overhead is incurred in the initial read, and not at run time. It takes billions of times longer for the user to type a statement into arc than it takes arc to denil the input. And after that, nil or () isn't an issue because arc functions are compiled to scheme functions anyways.

-----

2 points by absz 6633 days ago | link

I'm fairly sure that "the code is the spec" applies to arc.arc, not to ac.scm. That is, anything that can interpret arc.arc properly is a conforming Arc implementation; ac.scm is just one of them. And since nil is (), then in Arc, your two lists are the same but with different formatting. Observe:

  arc> (is nil '())
  t
  arc> (is nil ())
  t
  arc> (iso '(a b c) '(a . (b . (c . nil))))
  t
  arc> (iso '(a b c) '(a . (b . (c . ()))))
  t
  arc> (iso '(a . (b . (c . nil))) '(a . (b . (c . ()))))
  t

-----

2 points by eds 6633 days ago | link

Please note that the behavior of is is defined by ac.scm, not arc.arc. (And iso uses is to test for equality.)

The equality and interchangability of nil and () is just because there is a line in the definition of is that specifically says that false values are equal.

  (xdef 'is (lambda args
              (tnil (or (all (lambda (a) (eqv? (car args) a)) (cdr args))
                      (and (all string? args)
                           (apply string=? args))
                      (all ar-false? args)))))
  
  (define (ar-false? x)
    (or (eq? x 'nil) (eq? x '()) (eq? x #f)))
So even if you put #f in the terminating position, your lists will still be iso.

  arc> (iso '(a b c) '(a b c . #f))
  t
Are you saying that arc lists are #f terminated just because it doesn't break arc to put #f in random lists? Even if arc lists can be terminated by nil, (), and #f, it doesn't mean they necessarily are. Any given list (ignoring nested lists) can only have one termination object. I think it is reasonable to say that that list is terminated by that object. I do not think it is reasonable to say that list is terminated by another object, even if it could be, because the actual object at the end of the list is not that other object. And because the current implementation (the only official implementation) uses nil, I think it reasonable to say that arc lists are terminated by nil. Note the use of the present tense. If that changes at some future time, I my statement will obviously not apply.

-----

2 points by absz 6632 days ago | link

What you say is true, except for one thing:

  arc> (is #f nil)
  t
In short, given the current implementation, we have (at least) six different ways to write nil: nil, 'nil, (), '(), #f, and '#f. These six things are all considered identical within Arc. The same is true, for instance, of 'a and (quote a), which are the same thing entered differently. You can check that they are the same with is; I won't put all those examples into this post.

I have never said that Arc lists aren't nil terminated--clearly, they are. What I'm saying is that Arc lists are nil terminated for any representation of nil--whether that representation is nil from Common Lisp, '() from Scheme, or #f from a leftover artifact of using the mzscheme reader.

-----