Granted, this was referring to a different Scheme's implementation, but I think the basics hold. Not that it's a specific "why", but it would appear that several different implementations of Arc have been tried and the MzScheme one stuck for reasons being explored in this thread.
On the other hand, it's good that you can easily extend Lisps with virtually any control structure you want. To each their own, so far as the parentheses-laden cond vs. parentheses-lacking if issue goes.
The problem with multiple values being subsequent accesses is it would also interfere with a useful syntax (not actually in Arc, but I mean insofar as deciding which it should mean), and that's subsequence indexing. It's been discussed all over the place, e.g. http://arclanguage.org/item?id=449
With the assumption that one of them takes that syntax, what should be used for the other? How about (seq '(0 3 ...)) or (seq (0 3 ...))? It would similarly be fitting for any number of arguments, be they dimensions or indices, though I would vouch to use the list for n-dimensional indexing as the case of subsequences seems more common. Plus the use of a list distinguishes the one type of access from the other without having to go (...((seq 0) 3) ...).
Not that any of this helps your problem. Just something I noticed.
; Cartesian product of elements of menu
(def choices (menu (o result '()))
(if menu
(each x (car menu)
(choices (cdr menu) (join result (list x))))
(prall result "\n" " ")))
(choices (list
(list "small" "medium" "large")
(list "vanilla" "ultra chocolate" "lychee" "rum raisin" "ginger")
(list "cone" "cup")))
Ah, I was wondering why append wasn't working, haha. Now I recall reading the source about how Robert Morris thought it was better to overload + for join -- which still seems to work, by the way.
Also, come to think of a nit-picky issue, optional args will default to nil = '(), so you could just as well say:
(def choices (menu (o result))
(if menu
(each x (car menu)
(choices (cdr menu) (+ result (list x))))
(prall result "\n" " ")))
Not that it matters all that much.
One artifact I notice is that, since it returns nil but is only printing a newline at the beginning, the printout ends with "large ginger cupnil". I suppose, to avoid that in the repl, you could slap a (prn) at the end of the function definition or use the aforementioned (do ...) block. I got to thinking it might also be nice to have a prnall, but then I noticed that this is just prn:
(def choices (menu (o result))
(if menu
(each x (car menu)
(choices (cdr menu) (+ result (list x))))
(apply prn (intersperse " " result))))
Though this could be cleaner with prnall:
(def prnall args
(do1 (apply prall args) (prn)))
At any rate, all these thoughts are very pedantic -- but then, so am I.
This same idea of having the "step" parameter maps nicely into subseq syntax in Python, as I noted in this thread: http://www.arclanguage.org/item?id=479
The one way that it might not work so hot in an s-expression is Python's blanking-out of indexes to indicate the default, e.g.,
"abcdefghi"[::-2] #=> "igeca"
I'd like to see as much of this sort of range functionality as possible -- it's quite convenient -- but in an s-expression the above would be something like
("abcdefghi" -2) ;no distinction!
Perhaps use _ or some other symbol for the default? The cleanest would probably be to stick to the one-plus-optional-second-or-third format and just have a function that collects every nth element (then negative steps with default begins / ends would also be a chain of rev and firstn / nthcdr). Just my two cents.
prn used alone would have a return value of simply "hello, ". With tostring, the return value is "hello, world\n".
Though it might be worth noting that in the source file, arc.arc, there looks to be the beginnings of a printf-like function:
(let argsym (uniq)
(def parse-format (str)
(rev (accum a
(with (chars nil i -1)
(w/instring s str
(whilet c (readc s)
(case c
#\# (do (a (coerce (rev chars) 'string))
(nil! chars)
(a (read s)))
#\~ (do (a (coerce (rev chars) 'string))
(nil! chars)
(readc s)
(a (list argsym (++ i))))
(push c chars))))
(when chars
(a (coerce (rev chars) 'string)))))))
(mac prf (str . args)
`(let ,argsym (list ,@args)
(pr ,@(parse-format str))))
)
So that you could say, apparently:
(let var "world"
(prf "hello, ~" var))
Granted, the hello world example isn't very illuminating as to the benefits of using prf over the regular pr / prn. But, hey, the option's there in some base form (after all, the code's rather experimental at this stage).
I suspect it is a debugging thing. Since pr and prn return their first argument verbatim you can put them in the middle of working code to find what the return value of something is, without breaking anything. As a trivial example:
(+ (prn 2) 3) ; prints 2 and returns 5
Maybe you wouldn't need it if you had a fancy debugging suite, but it can be useful if you are debugging manually.
I think the reason is that returning the concatenation would be very expensive. It would basically require a temporary write stream just to put together the return value. In the majority of cases, the return value is probably not even used.
To get the effect you want, simply concatenate as a separate step: