Будет ли процедура рассматриваться как предикат <p>, если в специальной форме cond отсутствует ключевое слово else? - PullRequest
1 голос
/ 29 января 2020

Я случайно забыл поставить else в следующем выражении cond, и произошло нечто странное.

(define (abs x)
  (cond ((< x 0) x)
        ((= x 0) 0)
        (+ 1 2 1001)
        ))

> (abs 1)
1001
> 

результат (abs 1) не является результатом (+ 1 2 1001) ,, что равно 1004, но последний элемент аргументов выражения (+ 1 2 1001).

формы cond равен

(cond (<p1>,<e1>)
      (<p2>,<e2>)
      (<p3>,<e3>)
      ...
      (<pn>,<en>))

, в выражении (+ 1 2 1001) отсутствует предикат, поэтому Интересно, была ли процедура + рассмотрена как предикат, и всегда ли она оценивается как истина, выбирая последний элемент для возврата. Это так работает ???

Ответы [ 3 ]

5 голосов
/ 29 января 2020

Секвенирование : begin Форма в Racket позволяет упорядочить несколько выражений. Он оценивает каждое выражение слева направо, а конечный результат является последним выражением.

Синтаксис : синтаксис для cond показывает, что несколько выражений могут быть упорядочены в правой части пункта без begin. Такая вещь называется неявное начало .

Семантика : Согласно документации, cond оценивает rhs предложения, если lhs не равно #f. Следовательно, + в позиции test-expression оценивает rhs предложения.

Стиль : условно использование квадратных скобок в нескольких ключевых местах делает код Racket еще более читабельным. пункт cond является одним из этих мест.

Следующий фрагмент эквивалентен вашему фрагменту:

#lang racket

(define (abs x)
  (cond [(< x 0) x]
        [(= x 0) 0]
        [+ (begin 1
                  2
                  1001)]))
(abs 1) 
; => 1001
4 голосов
/ 29 января 2020

cond работает следующим образом:

(cond (test-expr then-body) 
      (test-expr2 then-body2)
      (else then-body3))

Test-expr проверяются один за другим, и первый test-expr, который возвращает не ложное значение, вызывает его соответствующее тогда тело должно быть выполнено. Последнее значение в выполняемом теле-теле - это значение всего условия.

В схеме все, что не #f, считается истинным. Следовательно, + считается верным. В вашем cond, + действует как else, потому что это всегда верно. Фактически, ваш код может быть написан так без каких-либо изменений в поведении:

(define (abs x)
  (cond ((< x 0) x)
        ((= x 0) 0)
        (else 1 2 1001)))

В вашем исходном коде первый тест-expr, который возвращает не ложное значение, равен +. Поскольку 1001 является последним значением выполненного тела тогда, 1001 является значением всего cond. Вот почему вы получили 1001.

3 голосов
/ 29 января 2020

cond - это способ сделать if-elseif * -почему в lisp и получить более плоскую структуру, чем при вложенности if. Поскольку cond является производной формой, вы можете написать условное выражение в терминах if. Ваша процедура будет выглядеть так:

(define (abs x)
  (if (< x 0) 
      x
      (if (= x 0) 
          0
          (if +
              (begin
                1 
                2 
                1001)))))

Последний if проверяет, является ли + правдивым. Каждое выражение , которое не оценивается как #f, является правдивым, поэтому все процедуры являются ложными. Затем он будет оценивать каждую часть 1, 2, затем 1001, и, поскольку это хвостовое выражение, является результатом оценки. Вы можете иметь столько же последствий в каждом семестре cond, но все до хвоста только для эффекта.

Вы можете добавить одну дополнительную пару скобок, и она будет работать так, как вы ожидали:

(define (abs x)
  (cond ((< x 0) x)
        ((= x 0) 0)
        ((+ 1 2 1001))))

Здесь нет никаких зависимостей, и истинный результат предиката является результатом для (abs 1). Хотелось бы, чтобы код был как можно более понятным, поэтому использование else является гораздо лучшим вариантом:

(define (abs x)
  (cond ((< x 0) x)
        ((= x 0) 0)
        (else (+ 1 2 1001))))

Это также помогает при другой проблеме. Хотя число всегда является правдивым, если вы выполняете трюк с предикатом с чем-то, что может быть #f, результат не определен в spe c. Таким образом:

  (cond ((other-proc x)))
  ; ==> ??

Если вызов other-proc правдив, результат таков, что если он равен #f, вы получите результат, выбранный исполнителями. Это почти всегда правдивые значения с сумасшедшими визуализациями, такими как #<undefined>, но могут быть что-то вроде "BaNaNa" или даже #f. Таким образом, разумно иметь термин else, чтобы вы, а не какой-либо другой разработчик, могли выбрать результат: -)

...