Unusual Scheme `let` binding, what is `f`?

scheme cond
scheme let vs define
scheme lambda
scheme begin
let: bad syntax (not an identifier and expression for a binding)
scheme set!
let vs letrec
let vs let* scheme

In "The Scheme Programming Language 4th Edition" section 3.3 Continuations the following example is given:

(define product
  (lambda (ls)
      (lambda (break)
        (let f ([ls ls])
            [(null? ls) 1]
            [(= (car ls) 0) (break 0)]
            [else (* (car ls) (f (cdr ls)))]))))))

I can confirm it works in chezscheme as written:

> (product '(1 2 3 4 5))

What is 'f' in the above let? Why is the given ls being assigned to itself? It doesn't seem to match what I understand about (let ...) as described in 4.4 local binding:

syntax: (let ((var expr) ...) body1 body2 ...)

If 'f' is being defined here I would expect it inside parenthesis/square brackets:

(let ([f some-value]) ...)

This is 'named let', and it's a syntactic convenience.

(let f ([x y] ...)
  (f ...)

is more-or-less equivalent to

(letrec ([f (λ (x ...)
              (f ...)
  (f y ...))

or, in suitable contexts, to a local define followed by a call:

(define (outer ...)
  (let inner ([x y] ...)
    (inner ...)

is more-or-less equivalent to

(define (outer ...)
  (define (inner x ...)
    (inner ...)
  (inner y ...))

The nice thing about named let is that it puts the definition and the initial call of the local function in the same place.

Cavemen like me who use CL sometimes use macros like binding, below, to implement this (note this is not production code: all its error messages are obscure jokes):

(defmacro binding (name/bindings &body bindings/decls/forms)
  ;; let / named let
  (typecase name/bindings
     `(let ,name/bindings ,@bindings/decls/forms))
     (unless (not (null bindings/decls/forms))
       (error "a syntax"))
     (destructuring-bind (bindings . decls/forms) bindings/decls/forms
       (unless (listp bindings)
         (error "another syntax"))
       (unless (listp decls/forms)
         (error "yet another syntax"))
       (multiple-value-bind (args inits)
           (loop for binding in bindings
                 do (unless (and (listp binding)
                                 (= (length binding) 2)
                                 (symbolp (first binding)))
                      (error "a more subtle syntax"))
                 collect (first binding) into args
                 collect (second binding) into inits
                 finally (return (values args inits)))
         `(labels ((,name/bindings ,args
            (,name/bindings ,@inits)))))
     (error "yet a different syntax"))))

Lexical Binding (MIT/GNU Scheme 10.1.11), The three binding constructs let , let* , and letrec , give Scheme block In a let expression, the initial values are computed before any of the variables (lambda (n) (if (zero? n) #t (odd? (- n 1))))) (odd? (lambda (n) (if (zero? n) #f (even? let Bindings. 05/16/2016; 5 minutes to read +1; In this article. A binding associates an identifier with a value or function. You use the let keyword to bind a name to a value or function.

f is bound to a procedure that has the body of let as a body and ls as a parameter.


Advances in Cryptology – CRYPTO 2017: 37th Annual International , CtE2 is not secure assuming just that CS is hiding and binding. The reason is Algorithm VerBad(M,K f ,C b) runs VerC(M,K f ,C) and outputs the result. An easy But if a scheme CS has unique commitments, then we can in fact show security of CtE2. Let A be an MO-RORCtE2 adversary making at most q oracle queries. A let binding that is not static is called an instance let binding. Instance let bindings execute when objects are created. Static let bindings are part of the static initializer for the class, which is guaranteed to execute before the type is first used. The code within instance let bindings can use the primary constructor's parameters.

Think of this procedure:

(define (sum lst)
  (define (helper lst acc)
    (if (null? lst)
        (helper (cdr lst) 
                (+ (car lst) acc))))
  (helper lst 0))

(sum '(1 2 3)) ; ==> 6

We can use named let instead of defining a local procedure and then use it like this:

(define (sum lst-arg)
  (let helper ((lst lst-arg) (acc 0))
    (if (null? lst)
        (helper (cdr lst) 
                (+ (car lst) acc)))))

Those are the exact same code with the exception of some duplicate naming situations. lst-arg can have the same name lst and it is never the same as lst inside the let.

Named let is easy to grasp. call/ccusually takes some maturing. I didn't get call/cc before I started creating my own implementations.

3.9 Local Binding: let, let*, letrec, All variable binding operations in Scheme are derived from lambda, except top-​level (let ((let 'let)) let) let. (define f (lambda (x) (g x))) (define g (lambda (x) (+ x x))) (f 3) 6 where temp are unique variables, one for each (var val) pair. The problem is that the Scheme compiler will treat sum occurring in the lambda expression as a different variable from the one introduced in the let binding. The occurence of sum in the lambda expression is global , whereas that introduced by the let binding is local.

Variable Binding, |(f 120 2) | (f 60 2) | |(f 30 2) | | (f 15 2) | | (f 15 3) | | |(f 5 3) | | |(f 5 4) | | |(f 5 5) | | |(5) | | (3 5) | |(2 3 5) | (2 Rewrite factor using letrec to bind f in place of named let. Semantics: Let* is similar to let, but the bindings are performed sequentially from left to right, and the region of a binding indicated by (<variable> <init>) is that part of the let* expression to the right of the binding. Thus the second binding is done in an environment in which the first binding is visible, and so on.

The Scheme Programming Language, (let ((x 7) (z (+ x y))) (* z x))) See also named let. section 11.16. 35 (let* (bindings) (body)) syntax Syntax: (Bindings) must have the form (((variable,) (ink,)) . The letrec-syntaxes+values form is the core form for local compile-time bindings, since forms like letrec-syntax and internal-definition contexts expand to it. In a fully expanded expression (see Fully Expanded Programs), the trans-id bindings are discarded and the form reduces to a combination of letrec-values or let-values.

Revised [6] Report on the Algorithmic Language Scheme, A Scheme expression is a construct that returns a value, such as a variable (​cond ((assv 'b '((a 1) (b 2))) => cadr) (else #f )) => 2 The three binding constructs let , let* , and letrec give Scheme a block (lambda (n) (if (zero? n) #t (​odd? All variable binding operations in Scheme are derived from lambda, except top-level occurrences of define, which establishes top-level bindings. Section 4.1. Variable References