SRFI 5: A compatible let form with signatures and rest arguments

▼ |  | SRFIs: Libraries

| SRFI 1: List Library
| SRFI 2: AND-LET*: an AND with local bindings...
| SRFI 4: Homogeneous numeric vector datatypes
| SRFI 5: A compatible let form with signatures and rest arguments
| SRFI 6: Basic String Ports
| SRFI 7: Feature-based program configuration language
| SRFI 8: RECEIVE: Binding to multiple values
| SRFI 9: Defining Record Types
| SRFI 11: Syntax for receiving multiple values
| SRFI 13: String Libraries
| SRFI 14: Character-set Library
| SRFI 16: Syntax for procedures of variable arity
| SRFI 17: Generalized set!
| SRFI 19: Time Data Types and Procedures
| SRFI 23: Error reporting mechanism
| SRFI 25: Multi-dimensional Array Primitives
| SRFI 26: Notation for Specializing Parameters without Currying
| SRFI 27: Sources of Random Bits
| SRFI 28: Basic Format Strings
| SRFI 29: Localization
| SRFI 30: Nested Multi-line Comments
| SRFI 31: A special form rec for recursive evaluation
| SRFI 34: Exception Handling for Programs
| SRFI 35: Conditions
| SRFI 38: External Representation for Data With Shared Structure
| SRFI 39: Parameter objects
| SRFI 40: A Library of Streams
| SRFI 41: Streams
| SRFI 42: Eager Comprehensions
| SRFI 43: Vector Library
| SRFI 45: Primitives for Expressing Iterative Lazy Algorithms
| SRFI 48: Intermediate Format Strings
| SRFI 54: Formatting
| SRFI 57: Records
| SRFI 59: Vicinity
| SRFI 60: Integers as Bits
| SRFI 61: A more general cond clause
| SRFI 62: S-expression comments
| SRFI 63: Homogeneous and Heterogeneous Arrays
| SRFI 64: A Scheme API for test suites
| SRFI 66: Octet Vectors
| SRFI 67: Compare Procedures
| SRFI 69: Basic hash tables
| SRFI 71: Extended LET-syntax for multiple values
| SRFI 74: Octet-Addressed Binary Blocks
| SRFI 78: Lightweight testing
| SRFI 86: MU & NU simulating VALUES & CALL-WITH-VALUES...
| SRFI 87: => in case clauses
| SRFI 98: An interface to access environment variables
| Index

On this page:

let

Racket
top contents ← prev up next →

## SRFI 5: A compatible let form with signatures and rest arguments🔗ℹ

(require srfi/5) | package: srfi-lib

Original specification: SRFI 5

For historical reasons, the SRFI 5 specification document has a restrictive license and is not included in the main Racket distribution.

The implementation in srfi/5 and this documentation are distributed under the same license as Racket: only the original specification document is restrictively licensed.

> > syntax
> > (let ([id init-expr] ...)
> > body ...+)
> (let ([id init-expr] ...+ rest-binding)
> body ...+)
> (let loop-id ([id init-expr] ... maybe-rest-binding)
> body ...+)
> (let (loop-id [id init-expr] ... maybe-rest-binding)
> body ...+)
> maybe-rest-binding |  | = |  |
> |  | | |  | rest-binding
> rest-binding |  | = |  | rest-id rest-init-expr ...

Like let from racket/base, but extended to support additional variants of named let.

As with let from racket/base, SRFI 5’s let form conceptually expands to the immediate application of a function to the values of the init-exprs: the ids are bound in the bodys (but not in any init-exprs or rest-init-exprs), and loop-id, if present, is bound in the bodys to the function itself, allowing it to be used recursively. An id or a rest-id can shadow loop-id, but the rest-id (if given) and all iss much be distinct.

SRFI 5’s let adds support for a syntax like define’s function shorthand, which allows the bindings to be written in a syntax resembling an application of the function bound to loop-id.

Additionally, SRFI 5’s let adds support for rest arguments. If a rest-id is present, the function bound to loop-id (or the conceptual anonymous function, if loop-id is not used) will accept an unlimited number of additional arguments after its required by-position arguments, and the rest-id will be bound in the bodys (but not in any init-exprs or rest-init-exprs) to a list of those additional arguments. The values of the rest-init-exprs are supplied as arguments to the initial, implicit application when the let form is evaluated, so the initial value bound to rest-id is (list rest-init-expr ...).

> > > Unlike the kw-formals of lambda and define or the formals of case-lambda, the bindings of SRFI 5’s let, with or without a rest-binding, are always a proper (syntactic) list.

A rest-binding can be used with both the define-like and the named-let–like variants of let. It is also possible to use rest-id without any loop-id; however, as specified in the grammar, at least one id–init-expr pair is required in that case. (Otherwise, there would be an ambiguity with the define-like variant).

Examples:

> ; define-like bindings
> > (define (factorial n)
> (let (fact [n n] [acc 1])
> (if (zero? n)
> acc
> (fact (sub1 n) (* n acc)))))
> > (factorial 5)
> 120
> > (factorial 11)
> 39916800
> ; rest arguments with named-let--like bindings
> > (let reverse-onto ([lst '(a b c)]
> tail)
> (if (null? lst)
> tail
> (apply reverse-onto (cdr lst) (car lst) tail)))
> '(c b a)
> > (let reverse-onto ([lst '(a b c)]
> tail 'x 'y 'z)
> (if (null? lst)
> tail
> (apply reverse-onto (cdr lst) (car lst) tail)))
> '(c b a x y z)
> > (let no-evens (lst 1 2 3 4 5)
> (cond
> [(null? lst)
> '()]
> [(even? (car lst))
> (apply no-evens (cdr lst))]
> [else
> (cons (car lst) (apply no-evens (cdr lst)))]))
> '(1 3 5)
> ; rest arguments with define-like bindings
> > (let (reverse-onto [lst '(a b c)] tail)
> (if (null? lst)
> tail
> (apply reverse-onto (cdr lst) (car lst) tail)))
> '(c b a)
> > (let (reverse-onto [lst '(a b c)] tail 'x 'y 'z)
> (if (null? lst)
> tail
> (apply reverse-onto (cdr lst) (car lst) tail)))
> '(c b a x y z)
> > (let (loop [continue? 0] args 'a 'a1 'a2)
> (case continue?
> [(0) (cons args (loop 1 'b))]
> [(1) (cons args (loop 2 'c 'd))]
> [else (list args)]))
> '((a a1 a2) (b) (c d))
> ; rest arguments without any loop-id
> > (let ([x 1]
> [y 2]
> z 3 4 5 6 7)
> (list* x y z))
> '(1 2 3 4 5 6 7)

top contents ← prev up next →