Почему книга How to Design Programs выбрала этот подход в своем листе ответов?

Я использую известную книгу Как разрабатывать программы. Точнее, первое издание (у меня есть физическое).

В 6-й главе есть несколько упражнений с Структурами. В одном из них нужно имитировать светофоры и использовать эффекты (мутации) для их изменения.

Я имею в виду упражнение упражнение 6.2. 5 о функции next, которая должна дать вам следующий цвет светофора.

Лист ответов, представленный в книге:

(start 50 160)
(draw-solid-disk (make-posn 25 30) 20 'red)
(draw-circle (make-posn 25 80) 20 'yellow)
(draw-circle (make-posn 25 130) 20 'green)

; -------------------------------------------------------------------------

;; clear-bulb : symbol -> true
;; to clear one of the traffic bulbs
(define (clear-bulb color)
  (cond
    [(symbol=? color 'red) 
     (and (clear-solid-disk (make-posn 25 30) 20)
          (draw-circle (make-posn 25 30) 20 'red))]
    [(symbol=? color 'yellow) 
     (and (clear-solid-disk (make-posn 25 80) 20)
          (draw-circle (make-posn 25 80) 20 'yellow))]
    [(symbol=? color 'green)
     (and (clear-solid-disk (make-posn 25 130) 20)
          (draw-circle (make-posn 25 130) 20 'green))]))

;; tests
(clear-bulb 'red)

; -------------------------------------------------------------------------

;; draw-bulb : symbol -> true
;; to draw a bulb on the traffic light
(define (draw-bulb color)
  (cond
    [(symbol=? color 'red) 
     (draw-solid-disk (make-posn 25 30) 20 'red)]
    [(symbol=? color 'yellow) 
     (draw-solid-disk (make-posn 25 80) 20 'yellow)]
    [(symbol=? color 'green)
     (draw-solid-disk (make-posn 25 130) 20 'green)]))

;; tests
(draw-bulb 'green)

; -------------------------------------------------------------------------

;; switch : symbol symbol -> true
;; to switch the traffic light from one color to the next
(define (switch from to)
  (and (clear-bulb from)
       (draw-bulb to)))

;; tests
(switch 'green 'yellow)
(switch 'yellow 'red)

; -------------------------------------------------------------------------

;; next : symbol -> symbol
;; to switch a traffic light's current color and to return the next one  
(define (next current-color) 
  (cond 
    [(and (symbol=? current-color 'red) (switch 'red 'green)) 
     'green] 
    [(and (symbol=? current-color 'yellow) (switch 'yellow 'red)) 
     'red] 
    [(and (symbol=? current-color 'green) (switch 'green 'yellow)) 
     'yellow]))

(next 'red)
(next 'green)
(next 'yellow)
(next 'red)

Со следующей функцией я сделал то же самое, что дало те же результаты в предоставленных тестах:

(define (next current-color) 
  (cond 
    [(symbol=? current-color 'red) (switch 'red 'green)] 
    [(symbol=? current-color 'yellow) (switch 'yellow 'red)] 
    [(symbol=? current-color 'green) (switch 'green 'yellow)]))

В отличие от ответа на книгу, мой код не использует and и не пропускает ни одного символа (например, «красный»).

Это отличие меня заинтриговало, поскольку в книге упор делается на то, чтобы научить вас разрабатывать код. Меня заинтриговал тот факт, что в исходном решении используется и (для объединения последующих эффектов), что кажется ненужным, кроме использования одиноких «красного», «желтого» или «зеленого» в конце каждого условное заявление.

Я не понимаю цели этого последнего утверждения символа или оператора and.

Есть ли какая-то стилистическая или концептуальная причина для такого подхода, который кажется более многословным и менее ясным?

Я читаю эту книгу именно для того, чтобы улучшить свой способ написания кода.


person Pedro Delfino    schedule 31.03.2021    source источник
comment
Это использование and для последовательности побочных эффектов является недостатком, который во втором издании исправлен путем перехода на более функциональный и более гибкий пакет обучения вселенной. Это гораздо более чистый дизайн, и я рекомендую хотя бы взглянуть на второе издание, чтобы увидеть, как это сделано там.   -  person Ryan Culpepper    schedule 31.03.2021


Ответы (1)


Racket, будучи своего рода Scheme, представляет собой язык, ориентированный на выражения< /эм>. Это означает, что последнее выражение в составном выражении является значением всего выражения.

Это включает символ в кавычках. Его значение, символ, является возвращаемым значением.

Вызов функции (next current-color) переключает цвет светофора и возвращает символ, обозначающий новый цвет светофора:

;; next : symbol -> symbol

Ваш код переключает цвет и возвращает true (согласно спецификации для switch):

;; switch : symbol symbol -> true
;; your-next : symbol -> true

Это меняет способ использования функции next. Благодаря дизайну книги мы можем написать

....
   (let loop ( ... )
       .....
       (let ((current-color (next current-color)))
           ......
           ))
....

С вашим дизайном такой естественный стиль зацикливания кода невозможен.

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

person Will Ness    schedule 31.03.2021
comment
Большой. Это было вне поля зрения для меня, когда я спросил. Это имеет смысл. То, что вы сказали, будет особенно полезно при использовании рекурсивных функций. Спасибо. - person Pedro Delfino; 31.03.2021
comment
Рад помочь. эти спецификации известны как типы BTW, и мы позволяем типам определять использование функций в нашем коде. они помогают нам видеть, что входит и что выходит, так что мы можем, так сказать, соединить соответствующие провода. :) счастливых троп, - person Will Ness; 31.03.2021
comment
Да. Раньше я беспокоился о типах только при использовании статически типизированных языков, таких как Standard ML. Так как Racket динамически типизируется, я особо не обращал внимания. Но есть причина, по которой в листе ответов используются комментарии для описания типов ввода-вывода. Я начну использовать комментарии перед функцией в качестве хорошей практики. - person Pedro Delfino; 31.03.2021