When to use lambda definition with a "bare" formal parameter?

670 views Asked by At

I'm learning Guile Scheme at the moment, and in the documentation I suddenly ran into the following construction:

((lambda args (display args)) 42)
=> (42)

This threw me for a loop; up until this point I had assumed formal parameters were always enclosed in a list:

((lambda (args) (display args)) 42)
=> 42

I wonder when to use this variant, and how this differs from the dot notation for variable number of arguments. Specifically, what is the difference between the two following variants:

((lambda args (display args)) 1 2 3)     => (1 2 3)
((lambda (. args) (display args)) 1 2 3) => (1 2 3)

Is there a difference — perhaps for more complex examples — that I need to be aware of and is there any reason to prefer one over the other?

2

There are 2 answers

2
Óscar López On BEST ANSWER

The difference is that this version receives a single parameter called args, useful for the cases when you know exactly the number of actual arguments expected for the lambda form:

(lambda (args) (display args))

And this version receives a (possibly empty) list of parameters, called args, useful when you expect a variable number of arguments for the lambda form:

(lambda args (display args))

There should be no difference between the following two versions, but not all interpreters will accept the second one, since it's missing the part before the dot (therefore it should be avoided):

(lambda args (display args))
(lambda (. args) (display args))

The following version is useful when you want to specify that a lambda form has one or more mandatory parameters (symbols to the left of the dot) and a list of zero or more optional parameters (a single symbol to the right of the dot):

(lambda (mandadory1 mandatory2 . optional) (display mandatory1))
1
Jonas On

This threw me for a loop; up until this point I had assumed formal parameters were always enclosed in a list:

Note that things like (a . args) and (a b . args) are not really lists either. (a . args) is a pair where the car is the symbol a and the cdr is the symbol args. (a b . args) is a pair where the car is the symbol a and the cdr is (a pair where the car is the symbol b and the cdr is the symbol args). It looks kind of like a list for a while, with the a and b and that, but as it doesn't end in null/the empty list it's not really a proper list. Structures like that are often called improper lists. If you wanna, you can read a little about the dotted-pair notation here, or somewhere else...

With (. args) I'd maybe say something like "it is a pair where the cdr is the symbol args". Or maybe it'd come out like "a pair where the car is and the cdr is args". Either way it wouldn't make a lot of sense, and, as Chris Jester-Young said, it's not really valid Scheme.

So. Things like (a b . args) are just regular dotted pair notation for putting things that aren't null in the last cdr. If the formal parameters-thing in Scheme can be one of those improper lists or a proper list or just a symbol, then the definition of the formal parameters-thing must be something like: a formal parameters-thing must be null, a symbol, or a pair where the car is a symbol and the cdr is a formal parameters-thing.

(Which I think is a kind of cool thing that makes for a rather elegant way of binding arguments to parameters. Like, you look at the formal parameters-thing, and if it's a symbol you bind the list of arguments to that and if it's a pair you bind the car of the arguments to the cdr of the formal parameters-thing and recur on cdr of the formal paramters-thing/arguments (oh and if it's null you're like done or something). That strikes me as a little bit prettier than the Common Lisp way of "and if the symbol in car is &rest you bind the rest of the arguments to the symbol after that".)