2010-12-30 3 views
5

В упражнении 18.1.12 от htdp, я переписал функцию maxi с помощью «local».Использование локальных в ракетке/схеме

;; maxi : non-empty-lon -> number 
;; to determine the largest number on alon 
(define (maxi alon) 
    (cond 
    [(empty? (rest alon)) (first alon)] 
    [else (local ((define m (maxi (rest alon)))) 
      (cond 
       [(> (first alon) m) (first alon)] 
       [(> m (first (rest alon))) m] 
       [else (first (rest alon))]))])) 

Я не знаю, почему я хотел бы сделать это в «реальной жизни», как это кажется версия книги короче, яснее и, вероятно, быстрее, а также.

(define (maxi alon) 
    (cond 
    [(empty? (rest alon)) (first alon)] 
    [else (cond 
     [(> (first alon) (maxi (rest alon))) (first alon)] 
     [else (maxi (rest alon))])])) 

Должно ли это быть чисто педагогическим упражнением? Может ли опытный разработчик прокомментировать код выше? Спасибо.

+0

Ну, вот вопрос [Сократ] (http://en.wikipedia.org/wiki/Socratic_questioning) для вас: Почему вы считаете, что версия, отличная от '' local ', скорее всего, быстрее? Я опубликую реальный ответ на этот вопрос, услышав ваши мысли. :-) –

+0

Sifu Chris, спасибо, что расспрашивали мои ASS-umptions. Я научился ценить ваше понимание все больше и больше. Похоже, что «локальная» версия намного быстрее, чем «чистая» рекурсивная версия, когда список становится большим. Я пришел к такому выводу, назвав функцию времени в списке с 20 номерами и был поражен, увидев среднюю разницу в производительности в 550 раз. Я не знаю, как Racket/Scheme работает внутри, чтобы объяснить несоответствие. Выполнение «локальной» версии, похоже, показывает, что 20 версий локальной функции «m» производят значение. – Greenhorn

ответ

3

Лично я считаю, что это плохой пример важности local, и я не верю, что вы полностью поняли важность вопроса, поэтому я сделаю это через концепцию, которую вы должны заметить, через ваш пример и, наконец, дать вам лучший пример.

CONCEPT

Во-первых, идея местного здесь (среди многих других вещей), чтобы разъяснить смысл из фрагментов кода.

ВАШ ПРИМЕР

Давайте рассмотрим ваш пример, можно определить локальную константу с именем m которая, как представляется правильным. Хотя, поскольку письмо m не имеет значительного значения, ваше решение кажется неясным. Итак, как мы можем исправить ваше решение?

Мы должны указать m имя, которое ясно обозначает то, что представляет m. Итак, мы начинаем непосредственно с учетом того, что m представляет что (maxi (rest alon))

Ну (maxi (rest alon)) просто говорит, найти максимальное количество (rest alon)

Так позволяет переименовать m в find-max

Теперь ваш код выглядит следующим образом:

;; maxi : non-empty-lon -> number 
;; to determine the largest number on alon 
(define (maxi alon) 
    (cond 
    [(empty? (rest alon)) (first alon)] 
    [else (local ((define find-max (maxi (rest alon)))) 
      (cond 
       [(> (first alon) find-max) (first alon)] 
       [(> find-max (first (rest alon))) find-max] 
       [else (first (rest alon))]))])) 

Замена m на find-max делает код более понятным! Оставив нас с правилом большого размера, дайте константам значащие имена.

МОЙ ПРИМЕР

Для дальнейшего уточнения, давайте рассмотрим функцию, которая потребляет две точки и производит наклон сегмента линии, созданной путем соединения двух точек. Наш первый подход может быть:

;;where x1,y1 belong to point 1 and x2,y2 belong to point 2 
(define (find-slope x1 y1 x2 y2) 
    (sqrt (+ (sqr (- x2 x1))) (sqr (- y2 y1)))) 

Но мы могли бы быть более ясным, используя local:

(define (find-slope x1 y1 x2 y2) 
    (local 
    [(define delta-x (- x2 x1)) 
    (define delta-y (- y2 y1))] 
    (sqrt (+ (sqr delta-x)) (sqr delta-y)))) 

Обратите внимание, как дельта описывает то, что функция делает в этой части; находя изменение x или y. Итак, что нам нужно узнать здесь, так это то, что, хотя первое решение может использовать меньше кода, второе решение описывает то, что мы делаем, и его можно легко прочитать.В этом была вся идея вопроса, и это может показаться глупым, но это конвенция, которую они склонны подчеркивать при изучении схемы в академической среде.

Что касается эффективности первого и второго решений, второе решение, безусловно, намного быстрее по понятным причинам (после того, как вы посмотрите, как Racket оценивает выражения), но это не было основной целью вопроса.

Надеется, что это помогает

+0

Спасибо, Адриан, за то, что нашли время, чтобы четко объяснить ситуацию! Я в твоем долгу. – Greenhorn

+0

Без проблем - рад помочь. –

3

Вместо использования local, можно пойти и используя внутренние определения ракетки (особенно с более поздними версиями).

Например:

(define (maxi alon) 
    (cond 
    [(empty? (rest alon)) (first alon)] 
    [else (define m (maxi (rest alon)))  ; here is an internal define 
      (cond 
      [(> (first alon) m) (first alon)] 
      [(> m (first (rest alon))) m] 
      [else (first (rest alon))])])) 
+2

Обратите внимание, что внутренние определения (по назначению) недоступны на учебных языках. Чтобы подчеркнуть, что определения являются локальными, нужно использовать «local». – soegaard

0

Использование локальных это способ быстрее, так как здесь он оценивает только (maxi (rest alon)) один раз в рекурсии, в то время как со второй версией он оценивает (maxi (rest alon)) дважды, когда он попадает в последнем случае.

Local сохраняет результат, поэтому вы не выполняете эту же работу дважды.

Смежные вопросы