1
votes

Schéma inhabituel liant `let`, qu'est-ce que` f`?

Dans "The Scheme Programming Language 4ème édition" section 3.3 Continuations l'exemple suivant est donné:

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

Je peux confirmer que cela fonctionne dans chezscheme comme écrit:

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

Qu'est-ce que « f » dans le let ci-dessus? Pourquoi le ls donné est-il attribué à lui-même? Cela ne semble pas correspondre à ce que je comprends de (let ...) comme décrit dans 4.4 liaison locale :

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

Si ' f ' est défini ici, je l'attendrait entre parenthèses / crochets:

(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)))]))))))


0 commentaires

3 Réponses :


1
votes

f est lié à une procédure qui a le corps de let comme corps et ls comme paramètre.

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


0 commentaires

2
votes

Ceci est 'nommé let', et c'est une commodité syntaxique.

(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"))))

est plus ou moins équivalent à

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

ou, dans des contextes appropriés, à un define local suivi d'un appel:

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

est plus ou moins équivalent à

XXX

La bonne chose à propos de let nommé est qu'il met la définition et l'appel initial de la fonction locale au même endroit.

Cavemen comme moi qui utilise CL utilise parfois des macros comme binding , ci-dessous, pour implémenter cela (notez que ce n'est pas du code de production: tous ses messages d'erreur sont des blagues obscures):

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


3 commentaires

TWIMC: "CL" == "Common Lisp". comme nous savons tous , Lisp n'a pas de syntaxe! ;) Common Lisp d'autant plus. Toutes ses constructions, commençant par prog , ne sont que des S-expressions! ;)


@WillNess: Lisp a beaucoup de syntaxe. En effet, puisque sa syntaxe est extensible par l'utilisateur, elle en a une quantité illimitée. Ce qu'il n'a pas habituellement, c'est beaucoup de syntaxe lexicale .


@tfb Merci, votre réponse a bien clarifié cela. Puisque je suis un amateur de stratagèmes au mieux, cette forme particulière a échappé à mon attention parce que je n’ai pas lu toutes les informations sur la récursivité. J'aurais aimé qu'il soit expliqué dans la section let normale, ou bien référencé clairement dans cette section avec le nom de la section dans laquelle il est réellement défini, ou qu'il ait un autre nom comme "letrec-and-execute"



0
votes

Pensez à cette procédure:

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

Nous pouvons utiliser let nommé au lieu de définir une procédure locale et ensuite l'utiliser comme ceci:

(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

Ce sont exactement le même code à l'exception de certaines situations de dénomination en double. lst-arg peut avoir le même nom lst et ce n'est jamais le même que lst dans le laissez .

Le nom let est facile à comprendre. call / cc prend généralement un peu de maturation. Je n'ai pas reçu call / cc avant de commencer à créer mes propres implémentations.


0 commentaires