For Gauche 0.9.5

Next: , Previous: , Up: Core syntax   [Contents][Index]

4.3 Making Procedures

Special Form: lambda formals body …
Special Form: ^ formals body …

[R7RS+] Evaluates to a procedure. The environment in effect when this expression is evaluated is stored in the procedure. When the procedure is called, body is evaluated sequentially in the stored environment extended by the bindings of the formal arguments, and returns the value(s) of the last expression in the body.

^ is a concise alias of lambda. It is Gauche’s extension.

(lambda (a b) (+ a b))
  ⇒ procedure that adds two arguments

((lambda (a b) (+ a b)) 1 2) ⇒ 3

((^(a b) (+ a b)) 1 2)       ⇒ 3

Gauche also extends R7RS lambda to take extended syntax in formals to specify optional and keyword arguments easily. The same functionality can be written in pure R7RS, with parsing variable-length arguments explicitly, but the code tends to be longer and verbose. It is recommended to use extended syntax unless you’re writing portable code.

Formals should have one of the following forms:

Macro: ^c body …

A shorthand notation of (lambda (c) body …). where c can be any character in #[_a-z].

(map (^x (* x x)) '(1 2 3 4 5)) ⇒ (1 4 9 16 25)
Macro: cut expr-or-slot expr-or-slot2 …
Macro: cute expr-or-slot expr-or-slot2 …

[SRFI-26] Convenience macros to notate a procedure compactly. This form can be used to realize partial application, a.k.a sectioning or projection.

Each expr-or-slot must be either an expression or a symbol <>, indicating a ’slot’. The last expr-or-slot can be a symbol <...>, indicating a ’rest-slot’. Cut expands into a lambda form that takes as many arguments as the number of slots in the given form, and whose body is an expression

  (expr-or-slot expr-or-slot2 …)

where each occurrence of <> is replaced to the corresponding argument. In case there is a rest-slot symbol, the resulting procedure is also of variable arity, and all the extra arguments are passed to the call of expr-or-slot. See the fourth example below.

(cut cons (+ a 1) <>)  ≡ (lambda (x2) (cons (+ a 1) x2))
(cut list 1 <> 3 <> 5) ≡ (lambda (x2 x4) (list 1 x2 3 x4 5))
(cut list)             ≡ (lambda () (list))
(cut list 1 <> 3 <...>)
   ≡ (lambda (x2 . xs) (apply list 1 x2 3 xs))
(cut <> a b)           ≡ (lambda (f) (f a b))

;; Usage
(map (cut * 2 <>) '(1 2 3 4))
(for-each (cut write <> port) exprs)

Cute is a variation of cut that evaluates expr-or-slots before creating the procedure.

(cute cons (+ a 1) <>)
   ≡ (let ((xa (+ a 1))) (lambda (x2) (cons xa x2)))

Gauche provides a couple of different ways to write partial applications concisely; see the $ macro below, and also the pa$ procedure (see Combinators).

Macro: $ arg …

A macro to chain applications, hinted from Haskell’s $ operator (although the meaning is different). Within the macro arguments arg …, $ delimits the last argument. For example, the following code makes the last argument for the procedure f to be (g c d …)

  ($ f a b $ g c d ...)
  ≡ (f a b (g c d ...))

The $ notation can be chained.

  ($ f a b $ g c d $ h e f ...)
  ≡ (f a b (g c d (h e f ...)))

If $* appears in the argument list instead of $, it fills the rest of the arguments, instead of just the last argument.

  ($ f a b $* g c d ...)
  ≡ (apply f a b (g c d ...))

  ($ f a b $* g $ h $* hh ...)
  ≡ (apply f a b (g (apply h (hh ...))))

Furthermore, if the argument list ends with $ or $*, the whole expression becomes a procedure expecting the last argument(s).

  ($ f a b $ g c d $ h e f $)
  ≡ (lambda (arg) (f a b (g c d (h e f arg))))
  ≡ (.$ (cut f a b <>) (cut g c d <>) (cut h e f <>))

  ($ f a b $ g c d $ h e f $*)
  ≡ (lambda args (f a b (g c d (apply h e f args))))
  ≡ (.$ (cut f a b <>) (cut g c d <>) (cut h e f <...>))

The more functional the code becomes, the more you tempted to write it as a chain of nested function calls. Scheme’s syntax can get awkward in such code. Close parentheses tend to clutter at the end of expressions. Inner applications tends to pushed toward right columns with the standard indentation rules. Compare the following two code functionally equivalent to each other:

(intersperse ":"
             (map transform-it
                  (delete-duplicates (map cdr
                                          (group-sequence input)))))

($ intersperse ":"
   $ map transform-it
   $ delete-duplicates
   $ map cdr $ group-sequence input)

It is purely a matter of taste, and also this kind of syntax sugars can be easily abused. Use with care, but it may work well if used sparingly, like spices.

As a corner case, if neither $ nor $* appear in the argument list, it just calls the function.

  ($ f a b c) ≡ (f a b c)
Macro: case-lambda clause …

[R7RS][SRFI-16] Each clause should have the form (formals expr …), where formals is a formal arguments list as for lambda.

This expression evaluates to a procedure that accepts a variable number of arguments and is lexically scoped in the same manner as procedures resulting from lambda expressions. When the procedure is called with some arguments, then the first clause for which the arguments agree with formals is selected, where agreement is specified as for the formals of a lambda expression. The variables of formals are bound to the given arguments, and the expr … are evaluated within the environment.

It is an error for the arguments not to agree with the formals of any clause.

Next: , Previous: , Up: Core syntax   [Contents][Index]