2017-02-11 23 views
1

В Ракетка можно определить порядок и константы внутри другой процедуры, например, как это:Racket - это форма определения в процедуре, выполняемой несколько раз?

(define (a a-list) 
    (define something 10) 
    (display a-list) 
    (cond 
    [(empty? a-list) (display "done")] 
    [else 
     (display a-list) (newline) 
     (a (rest a-list))])) 

Печать списка, а затем убирая первый элемент, а затем напечатав список еще раз и так далее, пока список пуст.

В примерной процедуре значение something определено по умолчанию как 10. Когда процедура повторяется, делает ли Racket значение снова или достаточно ли достаточно, чтобы заметить, что это определение не меняется?

Также он, вероятно, будет находиться в пространстве стека ранее названной процедуры, если это не оптимизировано, и оно будет потреблять еще немного памяти на каждый рекурсивный шаг, в зависимости от того, что определено как something. Например, можно сказать, что миллион номеров в списке, но никогда не меняет числа. Очевидно, что если вещи внутри этого определения зависят от списка, заданного как параметр, его нельзя просто оптимизировать.

Если это не оптимизировано, полезно ли иметь слишком много форм define внутри рекурсивной функции или только те, которые потребляют мало места? Внедрение их вне процедур сделает их доступными из других процедур, хотя даже если только одна из них когда-либо использует их.

ответ

1

Выражение define: оценивается каждый раз при вызове процедуры. Рассмотрим следующий пример:

(define (test1) 
    (define x (begin (display "Hello from test1 ") 10)) 
    x) 

(test1) 
=> Hello from test1 10 
(test1) 
=> Hello from test1 10 
(test1) 
=> Hello from test1 10 

Если вы хотите значение внутри процедуры должны оцениваться только один раз (когда сама процедура создания), вы можете поместить его в рамки вне процедуры, она все еще будет доступен поскольку lambda определяет closure над его лексическим окружением:

(define test2 
    (let ((x (begin (display "Hello from test2") 20))) 
    (lambda() x))) 

=> Hello from test2 
(test2) 
=> 20 
(test2) 
=> 20 
(test2) 
=> 20 
+0

Я не понимаю, первый пример. Конечно, когда я вызываю процедуру, она будет печатать это значение 'x'. Мне интересно, если есть оптимизация, идущая за кулисами, чтобы избежать необходимости определять значение 'x' каждый раз, потому что это одно и то же каждый раз. Совет о том, как сделать это с закрытием, кажется большим, хотя, если нет такой оптимизации для неизменных определений в процедурах (а может быть, и вообще?). Возможно, мне следовало спросить что-то вроде: «Разве JIT Racket оптимизирует определения неизменных значений в процедурах?» _ – Zelphir

+1

Вы не получите его - да, он печатает 'x', но он также печатает значение в 'display' part_, каждый раз. Определения должны оцениваться каждый раз, это не оптимизируется. –

+0

А теперь я понял! Благодаря! Я не понимаю, почему это было бы совершенно неоптимизировано, независимо от того, какое это определение. Я имею в виду нечто вроде '(define a 10)' и другое неизменное определение значений. Итак, я думаю, было бы хорошей практикой использовать то, как вы использовали во втором примере, чтобы избежать многократного повторения одной и той же неизменной вещи? – Zelphir