Arc Forumnew | comments | leaders | submitlogin
Top 10 differences between Scheme and Arc
17 points by kens 4388 days ago | 42 comments
I'm trying to summarize the differences between Scheme and Arc. I've come up with the following:

* Most functions have different names in Arc, and Arc provides a different set of functions.

* Arc provides the [ _ ] syntax.

* Arc's macro system is entirely different from Scheme's.

* Tables, strings, and lists can be treated as functions in Arc.

* Arc uses t and nil for true and false, rather than #t and #f

* Arc lists are terminated with nil, rather than '(). As a consequence, the empty list is false in Arc, rather than true in Scheme.

* Arc provides a user-defined type system through annotate. Types are exposed more directly in Arc through isa, type, and coerce.

* Arc supports special syntax with :, ~, !, and .

Any others? Errors?

7 points by drcode 4388 days ago | link

destructuring is available "for free" all commands that handle parameter lists (def, fn, rfn, afn, let, with, withs)

Arc is designed to minimize the equation (library functions count)*(end user code size)

list manipulation functions can handle strings as well (still incompletely supported)

structure support with deftem


8 points by cadaver 4388 days ago | link

Scheme uses the convention to place ? and ! at the end of the names for predicate and setter procedures respectively. Arc has no comparable convention.

  Scheme:   Arc:
  pair?     acons
  number?   number
  set!      set
  set-car!  scar


6 points by kens 4388 days ago | link

A convention such as this (or Common Lisp's trailing p for predicates) seems like a good thing to me. Does Arc avoid it because it "costs" an extra character?


2 points by tokipin 4388 days ago | link

my guess is it avoids it because it's ugly. i may be in the minority for thinking that's a good reason


5 points by byronsalty 4387 days ago | link

Well I don't think it's ugly, but ugliness aside it's very descriptive in one char. I'd personally like to see this convention carried over. Ruby uses the same convention so it's not just Scheme.

If this was intentionally left out my guess would be that PG was trying to save those chars for something meaningful to the compiler (syntax) not for aesthetics.


1 point by are 4386 days ago | link

It should be possible to detect, at define-time, whether a function/macro has side-effects (see the ideas for a conservative purity analyzer in

So if the function/macro has side-effects, def/mac could e.g. also assign it to a second symbol with "!" appended.

'?' could also be done similarly, but would be more difficult. Here is a start:

def/mac should also assign its function/macro to a second symbol with "?" appended if:

1) The function/macro has no side-effects (no "!")

2) The function/macro has a least one argument

3) The function/macro could return the empty list


1 point by Jekyll 4383 days ago | link

join? ?

list? ?

sort? ?

first? ?

It's not doing it for me.

Leaving aside the issues of detecting a query, I think it's a really bad idea to have the compiler force (badly guessed) semantic knowledge on me.

It's my code, I wrote it, and I don't want any compiler telling me that a query that caches previous results must be imperative! and not end in a ? .

I also thing needlessly polluting a namespace with addition symbols is a bad idea. You only get one namespace in arc, try to preserve it for the future.


1 point by tokipin 4387 days ago | link

that makes sense. '!' is already being used (though the convention doesn't interfere with the syntax at the moment)

bear with me here, but '!' means the function isn't pure, right? if so, who cares? it seems like an ivory tower thing. ? is fine, though maybe prefix notation can be considered



5 points by absz 4387 days ago | link

Just because something is academic doesn't mean it's not worthwhile. For instance, map, keep, reduce, etc. are different if passed a function with side-effects. What happens if you give them a function which modifies the list as it's being traversed? A pathological example:

  arc> (= x (range 1 5))
  (1 2 3 4 5)
  arc> (map [do (= (cdr x) (cddr x)) _] x)
  (1 3 4 5)
  arc> x
However, if map is passed a pure function, you can e.g. run one copy of the function on each core and run it in parallel.

And "dangerSet" is both non-Lispy and non-Arcy. It's non-Arcy because it's long. And it's non-Lispy because of that capital letter: danger-set would be marginally better. But nevertheless, pair? is shorter than is-pair, and (in my opinion) reads much more nicely.


9 points by im 4388 days ago | link

You may be in the minority for thinking it's ugly.


8 points by ryantmulligan 4387 days ago | link

* arc has a budding community, scheme has an aging community

* arc has a designer/dictator, scheme has a committee

* arc has this forum, scheme has lots of scattered stuff


4 points by kennytilton 4388 days ago | link

1. You have eight, not 10 :)

2. "Arc lists are terminated with nil, rather than '()." is odd, because nil and '() are the same. Maybe modify the preceding remark to be "Arc uses t and '()/nil for true and false..." and lose this altogether.


7 points by tjr 4388 days ago | link

But then he'd only have seven.


3 points by kennytilton 4387 days ago | link

But Arc is an exercise in minimalism...hang on. pg is being pounded for Arc being too close to Lisp to be hundred-yeary, maybe we should pad the numbers. :)


5 points by pg 4388 days ago | link

Off the top of my head, another big one is that Arc has a more library functions. Individual Scheme implementations tend to, but the Scheme standard is pretty small.

There's also deftem.


5 points by shiro 4388 days ago | link

Not anymore with R6RS---it has over 650 functions. Besides, I tend to think SRFIs as a part of 'modern' Scheme, as some of them are quite essential for day-to-day programming. (Although the popularity varies a lot---cf. )


7 points by absz 4388 days ago | link

To be pedantic, '() and nil are synonyms. It's not that nil means #f, it's that the empty list is considered false.


6 points by Jekyll 4388 days ago | link

Scheme has arrays. Arc doesn't yet. Arc has a generic setter = . Scheme doesn't.


1 point by sacado 4388 days ago | link

Yes, arc has arrays, in the libraries of the unofficial version.


4 points by almkglor 4387 days ago | link

This "array" support is really for an abstract sparse array (with a hashtable implementation). I think what's being referred to is a "real array" (with a sequential-cells-of-memory implementation.)


1 point by Jekyll 4387 days ago | link

That's a shame. I was all excited for a minute.

I guess I'll have start poking about in the source this weekend and see how hard it is to push the functionality up from the underlying scheme.


1 point by almkglor 4387 days ago | link

While you're at it, try to see if it can be pushed up in lib/array.arc on the arc-wiki.


1 point by sacado 4387 days ago | link

Oh, sorry. I guess it has to be added then :)


3 points by sacado 4387 days ago | link

Do you think it is the right thing ? If so, I'll push it to the git. Nothing amazing there, just mzscheme vectors that can be called as hash tables, lists or string. It's got a constructor (vec) and responds to len. Any further function can (should) be written in Arc.

  arc> (= v (vec 10))
  arc> (= (v 1) 0)
  arc> (len v)
  arc> (v 0)
  arc> (v 1)
  arc> (v 10)
  Error: "vector-ref: index 10 out of range [0, 9] for vector: #10(nil 0 nil)"


2 points by almkglor 4387 days ago | link

Looks good. I vote for "push".

Edit: Although it might (?) be better in the lib/array.arc, unless of course it's already integrated into ac.scm...

Edit2: Also, I hope (vec ...) is a function, not a macro or special form, so that existing code that uses vec as a local variable for a collection, or as a function, can still work.


2 points by sacado 4387 days ago | link

It can't be put in a .arc file, since it is pure scheme code. Further functions dealing with vectors should go in lib/array.arc, however. And yes, vec is a function.


2 points by Jekyll 4387 days ago | link

That's awesome, but I've just lost all my motivation to learn git.

Nice work :D.


1 point by sacado 4386 days ago | link

It is still very basic. Many utilitary functions could be added on top of that if you want :)


1 point by sacado 4387 days ago | link

pushed. type on a vector also returns 'vec.


3 points by sacado 4388 days ago | link

arc has a tendancy to removes parentheses : e.g. in "cond" and "let"


1 point by Jesin 4388 days ago | link

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


arc> (is 1 2)


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


arc> '()


arc> (is '() nil)


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


1 point by eds 4388 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))

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

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

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

  arc> (cdr '(1 . ()))
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 4387 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 4387 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 4387 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 4387 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 4386 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 4386 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 4387 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 4387 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 '())
  arc> (is nil ())
  arc> (iso '(a b c) '(a . (b . (c . nil))))
  arc> (iso '(a b c) '(a . (b . (c . ()))))
  arc> (iso '(a . (b . (c . nil))) '(a . (b . (c . ()))))


2 points by eds 4386 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))
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 4386 days ago | link

What you say is true, except for one thing:

  arc> (is #f nil)
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.