Необычная схема `let` обязательна, что такое` f`? - PullRequest
1 голос
/ 19 октября 2019

In "Язык программирования схем 4-е издание" раздел 3.3 Продолжения приведен следующий пример:

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

Я могу подтвердить, что он работает в chezscheme какнаписано:

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

Что такое 'f' в вышеприведенном let? Почему данный ls присваивается самому себе? Кажется, он не соответствует тому, что я понимаю о (let ...), как описано в 4.4 локальное связывание :

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

Если здесь определено 'f', я бы ожидалвнутри скобок / квадратные скобки:

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

Ответы [ 3 ]

2 голосов
/ 19 октября 2019

Это по имени let, и это синтаксическое удобство.

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

более или менее эквивалентно

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

или, в подходящих контекстах,local define, за которым следует вызов:

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

более или менее эквивалентен

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

Хорошая вещь в именованном let состоит в том, что он помещает определение ипервоначальный вызов локальной функции в том же месте.

Пещерные люди, подобные мне, которые используют CL, иногда используют макросы, подобные binding, ниже, для реализации этого (обратите внимание, что это не рабочий код: все его сообщения об ошибкахнеясные шутки):

(defmacro binding (name/bindings &body bindings/decls/forms)
  ;; let / named let
  (typecase name/bindings
    (list
     `(let ,name/bindings ,@bindings/decls/forms))
    (symbol
     (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
                     ,@decls/forms))
            (,name/bindings ,@inits)))))
    (t
     (error "yet a different syntax"))))
1 голос
/ 19 октября 2019

f связан с процедурой, которая имеет тело let в качестве тела и ls в качестве параметра.

http://www.r6rs.org/final/html/r6rs/r6rs-Z-H-14.html#node_sec_11.16

0 голосов
/ 21 октября 2019

Подумайте об этой процедуре:

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

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

Мы можем использовать именованную let вместо определения локальной процедуры, а затем использовать ее следующим образом:

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

Это точныетот же код, за исключением некоторых дублирующих ситуаций именования. lst-arg может иметь то же имя lst, и оно никогда не совпадает с lst внутри let.

Названный let легко понять. call/cc обычно требуется некоторое созревание. Я не получил call/cc до того, как начал создавать свои собственные реализации.

...