7

So, I am trying to see how functions that can accept any number of arguments work?

I tried this

(define (plus x . xs)
  (if 
   (null? xs) x
   (plus (+ x (car xs)) . (cdr xs))))
(plus 1 2 3 4)

But is seemed that it wasn't actually applying cdr to xs, but passing ( (2 3 4)) in when I stepped through it in the debugger. So I tried this

(define (plus* x . xs)
  (if 
   (null? xs) x
   (let ((h (car xs))
         (t (crd xs)))            
     (plus* (+ x h) . t))))

Thinking: "ha, I'd like to see you pass cdr in now", but I get an error: "application: bad syntax (illegal use of `.') in: (plus* (+ x h) . t)"

What is going on?

(I can get a version of addition to work, either by

(define (add . xs)
     (foldl + 0 xs))

Or even

(define (plus x . xs)
  (if 
   (null? xs) x
   (apply plus (cons (+ x (car xs))  (cdr xs)))))

so, the addition is not the problem, how dotted things work is.)

Theo Belaire
  • 2,980
  • 2
  • 22
  • 33

1 Answers1

7

Your last version is the correct way to pass a list of numbers as inputs to plus -- you must use apply to do this. (Well, either that, or avoid the whole thing as you did with foldl.) Using a dot in the application is not doing what you think it should -- it makes the program read differently.

Eli Barzilay
  • 29,301
  • 3
  • 67
  • 110
  • What does it do instead? How does one use the dot, if not like that? – Theo Belaire Nov 15 '10 at 05:29
  • 3
    `(x . y)` is read as a cons cell with `x` in its `car` and `y` in its cdr -- that is, it's not a proper list. Similarly, `(x . (y))` is a cons cell with `x` in its `car`, and the list `(y)` in its `cdr` -- so it's the same as reading `(x y)`. So when you write `(plus x . (cdr t))`, it's the same as if you wrote `(plus x cdr t)`, which explains the confusing results you got. – Eli Barzilay Nov 15 '10 at 07:50
  • Note BTW that Racket has a syntax system that makes it possible to distinguish between the two, and treat an expression that was entered with such a `.` differently -- but this is not done since it can lead to even greater confusion in other situations. – Eli Barzilay Nov 15 '10 at 07:51
  • Let does fail. I get "application: bad syntax (illegal use of `.') in: (plus* (+ x h) . t)". Same if I use the bare lambda form that let expands too. – Theo Belaire Nov 15 '10 at 21:08
  • I explicitly detailed in the above why that is a syntax error, regardless `let` or not -- you *need* to use `apply`. Period. – Eli Barzilay Nov 16 '10 at 04:31
  • I can see that. I want to know why. Why does wrapping it in a let change it from continuing with the wrong parameters to failing to compile at all? Does the dot quote what follows it? Is that why it didn't evaluate `(something . (cdr '(2 3 4)))` into `(something 3 4)`? – Theo Belaire Nov 16 '10 at 22:21
  • 1
    It's all in the above, the only other thing that might help you is to run `(read)` and enter your code with the dot -- then look at what is actually being read. – Eli Barzilay Nov 16 '10 at 23:55