Arc Forumnew | comments | leaders | submitlogin
confused by apply
2 points by conanite 6226 days ago | 6 comments
arc> (+ '(a b) '((c d) (e f))) (a b (c d) (e f)) arc> (apply + '(a b) '((c d) (e f))) (a b c d e f)

i'm completely missing something - why don't they both return the same result?



4 points by absz 6226 days ago | link

apply is designed for calling a function with a variable argument list. Conceptually, you can write any function call of the form (f a b c) as (apply f (list a b c)). Its arguments are a function, any number of arguments, and a list at the end. For instance, suppose we have (apply f x y z (list a b c)). This is the same as writing (f x y z a b c).

In your example, you have (apply + '(a b) '((c d) (e f))); apply splices in the closing list, doing the same thing as (+ '(a b) '(c d) '(e f)); it should be clear why this returns '(a b c d e f).

That was not the clearest explanation in the world, so if you still have questions, please ask.

Also, a formatting tip: indent your code with two spaces and surround it by blank lines to have it formatted as code.

-----

2 points by conanite 6225 days ago | link

Thanks. The behaviour of apply seems to be consistent with last-args-as-varargs.

  arc> (apply + "a" '("b" "c"))
  "abc"
I was originally thrown by a line in w/uniq in arc.arc -

  (apply + nil (map1 (fn (n) (list n '(uniq))) names))
This line is constructing an argument list for "with". It looks like the nil is necessary in case map1 returns an empty list, otherwise + would return 0, which is not a valid argument list.

(and thanks for the formatting tip)

-----

1 point by absz 6225 days ago | link

The reason that w/uniq has the nil is so that + thinks it's adding lists, not numbers. Of course, pg could have just used join there, which would (a) eliminate the typing problem, and (b) in the nil case, produce (join), which is nil.

Also, if you want to reply directly to a person, click on the reply link below their post; it makes following the conversation a little bit smoother :)

-----

2 points by jazzdev 6226 days ago | link

I think apply is typically supposed to take only 2 args:

  arc> (apply + '((a b) ((c d) (e f))))
  (a b (c d) (e f))
There's some special code that interprets apply with 3+ args differently. I don't know why apply with 3+ args is even allowed. Search ac.scm for ar-apply-args and there's a comment about it. It seems to have something to do with the arc/scheme boundary, but I don't really understand the comment.

-----

3 points by eds 6226 days ago | link

No, apply can take any number of args. The last arg is interpreted as a varargs parameter. This is in fact the entire reason 'apply exists at all, so it can expand the final list into individual args.

-----

1 point by absz 6226 days ago | link

Not quite. All that the comment is talking about is that Arc lists are different from Scheme lists. In Arc, they end with the symbol 'nil (e.g., '(1 2 3) is the same as '(1 2 3 . nil)); in Scheme, they end with '() (e.g., '(1 2 3) is the same as '(1 2 3 . ())).

apply is perfectly well-defined for n arguments: (apply f x xs) is the same as (apply f (cons x xs)). In other words, if we think about apply as providing the contents of a list as arguments to a function, this is only relevant to the last argument. The rest are passed to the function normally. This is a nicety, allowing us to write things like (apply map + list-of-lists).

-----