Schéma / Racket: faire pour boucle d'évaluation
-
02-10-2019 - |
Question
La procédure suivante est valable dans les deux r6rs régime et Racket:
;; 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 fonctionne bien, mais je sais seulement que sûr pour DrRacket.
Ma question est si elle est garantie que les expressions de l'étape ((- x 1)
et (cons x lst)
dans ce cas) seront évalués en ordre. Si ce n'est pas garanti, ma procédure n'est pas très stable.
Je ne vois rien préciser cela dans les normes pour les deux langues, mais je demande ici parce que quand je l'ai testé était evaulated dans l'ordre.
La solution
Ils sont généralement pas garantie à évaluer dans l'ordre, mais le résultat sera toujours le même. En effet, il n'y a pas d'effets secondaires ici -. La boucle ne change pas x
ou lst
, il suffit de les nouvelles valeurs de lie de nouveau, de sorte que l'ordre dans lequel les deux expressions sont évaluées étape est hors de propos
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]))
se traduire par un nom-let
:
(define (make-nums n)
(let loop ([x n] [lst null])
(if (zero? x)
lst
(loop (- x 1) (cons x lst)))))
et plus que traduire à une fonction d'assistance (qui est ce qu'un nom-let
est vraiment):
(define (make-nums n)
(define (loop x lst)
(if (zero? x)
lst
(loop (- x 1) (cons x lst))))
(loop n null))
Il doit être clair maintenant que l'ordre d'évaluer les deux expressions dans l'appel loop
récursive ne fait pas faire quelque chose de différent.
Enfin, notez que dans l'évaluation Racket garantie à 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 à code qui repose implicitement sur ce point. 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 pourraient renvoyer les deux lignes dans un ordre différent.