2016-11-02 3 views
0

Qu'est-ce qui différencie exactement ces implémentations de 'quand'?Différence entre une implémentation de 'quand' en tant que fonction et en tant que macro

(define-syntax when 
    (syntax-rules() 
    ((_ pred b1 ...) 
    (if pred (begin b1 ...))))) 

contre

(define (my-when pred b1 ...) 
    (if pred (begin b1 ...))) 

Par exemple, lorsque 'my-quand' est utilisé dans cette boucle macro:

(define-syntax for 
    (syntax-rules() 
    ((_ (i from to) b1 ...) 
    (let loop((i from)) 
     (my-when (< i to) 
        b1 ... 
        (loop (+ i 1))))))) 

une erreur se produit:

(pour (i 0 10) (affichage i))

; !: profondeur de l'interruption récursion maximale a dépassé

Je ne pense pas que « quand » peut être mis en œuvre en fonction, mais je ne sais pas pourquoi ...

Répondre

0

Le schéma a une sémantique stricte.

Cela signifie que tous les paramètres d'une fonction sont évalués avant que la fonction ne leur soit appliquée.

Les macros prennent le code source et produisent le code source - elles n'évaluent aucun de leurs paramètres.

(Ou, bien, je suppose qu'ils le font, mais leurs paramètres sont des éléments de langage de syntaxe - plutôt que ce que vous considérez normalement comme des valeurs, telles que des nombres ou des chaînes.La programmation macro est la métaprogrammation. vous savez à quel niveau vous programmez.)

Dans votre exemple, cela signifie que lorsque my-when est une fonction, (loop (+ i 1)) doit être évaluée avant que my-when ne puisse être appliquée.
Cela conduit à une récursion infinie.

Quand il est une macro, la forme my-when est d'abord remplacé par l'équivalent if -forme

(if (< i to) 
    (begin 
     b1 ... 
     (loop (+ i 1)))) 

puis est évalué la chose, ce qui signifie que (loop (+ i 1)) obtient seulement évalué quand la condition est vraie.

+0

Belle explication! Pouvez-vous clarifier pourquoi la boucle (+ i 1)) n'est évaluée que lorsque la condition est vraie? Pour moi, il semble que cela ne serait évalué que si la condition est fausse puisque la macro 'when' ne semble pas "utiliser" la boucle dans son instruction if. – wes

+0

@wes La boucle fait partie du "..:" de la macro 'my-when'. J'espère que la modification aide. – molbdnilo

0

Si vous implémentez when comme une procédure comme vous l'avez fait , alors tous les arguments sont évalués. Dans votre mise en œuvre for, l'évaluation serait traitée comme ceci:

  1. évaluer (< i to)
  2. évaluer résultat l'expansion de b1 ...
  3. (loop (+ i 1)) < évaluer - va ici en boucle infinie!
  4. évaluer my-when

article 1-3 peut être inversé ou undefined en fonction de votre mise en œuvre, mais le point est nr. 4. Si my-when est implémentée en tant que macro, la macro est la première à être évaluée.

Si vous avez vraiment besoin de mettre en œuvre avec une procédure, alors vous devez utiliser une sorte de truc de retard comme le thunk. Par exemple:

(define (my-when pred body) (if (pred) (body))) 
(my-when (lambda() (< i 10)) (lambda() (display i) (loop (+ i 1))))