Какая польза от «когда» в схеме? - PullRequest
2 голосов
/ 02 июня 2019

Я пытаюсь использовать, когда в Схеме, но я не знаю, почему на последнем элементе моего списка появляется. # Void>.

Вот мой код

(define (genlist x y)
   (when
       (< x y)
       (cons x (genlist (+ x 1) y))))

А это мой вывод =>

(2 3 4 5 6 7 8 9 . #void>)

Ответы [ 3 ]

2 голосов
/ 02 июня 2019

when - это один вооруженный ifs с неявным begin. Следующие примеры одинаковы:

(if (any odd? lst)
    (begin
      (set! some-binding #t)
      (display "Found an odd element")))


(when (any odd? lst)
  (set! some-binding #t)
  (display "Found an odd element"))

И вы можете использовать unless вместо not в предикате:

(if (not (any odd? lst))
    (set! some-binding #f))

(unless (any odd? lst)
  (set! some-binding #f))

Питер Норвиг написал хорошую книгу о стиле Лиспа и в ней он обращается к этому:

Будьте точны, как это требуется в абстракциях данных, но не более.

  • если для выражения с двумя ветвями
  • когда, за исключением оператора с одной веткой
  • и, или только для логических значений
  • cond для многоотраслевого оператора или выражения

Так что, хотя вы можете написать всю свою логику, используя if, это будет не самый простой код для чтения. Другие могут использовать термин принцип наименьшего удивления . Несмотря на то, что книга предназначена для Common Lisp, большая ее часть может быть использована и в Scheme. Это хорошее чтение, если вы хотите профессионально программировать любой диалект lisp.

Для when и unless это гораздо лучше применимо к Scheme, так как вы не представляете, что реализация может вернуть в случае, если предикат оценивается как #f, тогда как в CL вы можете злоупотреблять when, поскольку он предназначен вернуть nil в таких случаях.

В своем коде вы пытаетесь что-то вернуть и позволяете реализации выбирать, что должно произойти, когда предикат завершается ошибкой, и это вызывает #<void>. Когда возвращение имеет значение, вы всегда должны использовать два вооруженных if:

(if test-expression
    then-expression
    else-expression)

Обратите внимание, что ключевое слово else отсутствует.

2 голосов
/ 02 июня 2019

Вам потребуется использовать (if (< x y) (cons ...) '()) для создания правильного списка.

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

например. (when debug-mode? (print "got here"))

1 голос
/ 02 июня 2019

Мы используем when, когда нам нужно написать if без else части, и / или когда нам нужно написать более одного выражения внутри if. Возвращается только значение последнего выражения, поэтому мы используем его в основном для побочных эффектов. Чтобы лучше это понять, в Racket это:

(when <condition>
  <exp1>
  <exp2>
  <exp3>)

Эквивалентно этому:

(if <condition>
    (begin
      <exp1>
      <exp2>
      <exp3>)
    (void)) ; implementation-dependent

То же самое относится и к unless, за исключением того, что условие окружено (not ...).

Источник ваших проблем (и причина того, что код имеет запах if без else) заключается в том, что ваш код не обрабатывает случай, когда (>= x y). Спросите себя, что вы должны делать в этом случае? Просто верните пустой список! это базовый случай рекурсии, которого нет в вашем коде.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...