2010-09-14 20 views
3

La procédure suivante est valable dans les deux r6rs régime et Racket:Schéma/Racket: faire boucle ordre d'évaluation

;; create a list of all the numbers from 1 to n 
(define (make-nums n) 
    (do [(x n (- x 1)) (lst (list) (cons x lst))] 
    ((= x 0) 
    lst))) 

Je l'ai testé pour les deux r6rs et Racket et il ne fonctionne pas correctement, mais je ne Sachez que c'est sûr pour DrRacket.

Ma question est de savoir s'il est garanti que les expressions étape (dans ce cas (- x 1) et (cons x lst)) seront évalués en ordre. Si ce n'est pas garanti, alors ma procédure n'est pas très stable.

Je n'ai rien vu qui spécifie cela dans les normes pour l'une ou l'autre langue, mais je demande ici parce que quand j'ai testé cela a été évaulé dans l'ordre.

Répondre

7

Ils ne sont généralement pas garantis d'être évalués dans l'ordre, mais le résultat sera toujours le même. C'est parce qu'il n'y a pas d'effets secondaires ici - la boucle ne change pas x ou lst, elle les redéfinit juste à de nouvelles valeurs, donc l'ordre dans lequel les expressions en deux étapes sont évaluées est sans importance.

Pour voir cela, commencer par une version plus propre à la recherche de votre code:

(define (make-nums n) 
    (do ([x n (- x 1)] [lst null (cons x lst)]) 
     [(zero? x) lst])) 

traduit à un named- let:

(define (make-nums n) 
    (let loop ([x n] [lst null]) 
    (if (zero? x) 
     lst 
     (loop (- x 1) (cons x lst))))) 

et encore traduire à une fonction d'assistance (qui est ce que est un let) devrait être clair maintenant que l'ordre d'évaluer les deux expressions dans l'appel récursif loop ne le fait pas faire quelque chose de différent.

Enfin, notez que dans l'évaluation de raquette est garanti être de gauche à droite. Cela est important quand il y a des effets secondaires - Racket préfère un comportement prévisible, alors que d'autres s'y opposent, affirmant que cela conduit les gens à un code qui repose implicitement sur cela. Un petit exemple courant qui montre la différence est:

(list (read-line) (read-line)) 

qui Racket est garanti pour retourner une liste de la première ligne lue, puis la deuxième. D'autres implémentations peuvent renvoyer les deux lignes dans un ordre différent.

+0

Editer: Merci! C'est très intéressant, je n'avais pas réalisé que ça fonctionnait de cette façon. – Cam