Schema / Racket: fare l'ordine del ciclo di valutazione
-
02-10-2019 - |
Domanda
La seguente procedura è valida sia in R6RS schema e 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)))
Ho testato sia per R6RS e racchetta e funziona correttamente, ma so solo che di sicuro per DrRacket.
La mia domanda è se si tratta di garantito che le espressioni di passo ((- x 1)
e (cons x lst)
in questo caso) saranno valutate in ordine. Se non è garantito, allora la mia procedura non è molto stabile.
Non ho visto nulla di specificare questo nelle norme sia per la lingua, ma sto chiedendo qui perché quando ho provato è stato evaulated in ordine.
Soluzione
Si stanno generalmente non garantita da valutare in ordine, ma il risultato sarà comunque lo stesso. Questo è perché non ci sono effetti collaterali qui -. Il ciclo non cambia x
o lst
, semplicemente li rebinds a nuovi valori, in modo da l'ordine in cui vengono valutate le due espressioni passo è irrilevante
Per vedere questo, iniziare con una versione più pulita dall'aspetto del vostro codice:
(define (make-nums n)
(do ([x n (- x 1)] [lst null (cons x lst)])
[(zero? x) lst]))
tradursi in un-let
nome:
(define (make-nums n)
(let loop ([x n] [lst null])
(if (zero? x)
lst
(loop (- x 1) (cons x lst)))))
e l'ulteriore traduce che per una funzione di supporto (che è ciò che un-let
nome è in realtà):
(define (make-nums n)
(define (loop x lst)
(if (zero? x)
lst
(loop (- x 1) (cons x lst))))
(loop n null))
Dovrebbe essere chiaro ormai che l'ordine di valutare le due espressioni nella chiamata loop
ricorsiva non fargli fare qualcosa di diverso.
Infine, ricordiamo che nella valutazione Racket è garantito da sinistra a destra. Questo è importante quando ci sono effetti collaterali - Racket preferisce un comportamento prevedibile, mentre altri obiettano ad esso, sostenendo che questo porta le persone a codice che implicitamente si basa su questo. Un piccolo esempio comune che mostra la differenza è:
(list (read-line) (read-line))
che a sua Racket è garantito per restituire un elenco della prima linea di lettura, e poi la seconda. Altre implementazioni potrebbero restituire le due linee in un ordine diverso.