Вы ничего не можете вернуть из функции в Scheme? - PullRequest
10 голосов
/ 20 марта 2009

Я пишу интерпретатор схемы, и в случае оператора if, такого как:

(if (< 1 0) 'true)

Любой интерпретатор, которого я пробовал, просто возвращает новое приглашение. Но когда я закодировал это, у меня был вопрос, было ли альтернативное выражение. Что я могу вернуть, если ничего не напечатано?

(if (has-alternative if-expr)
  (eval (alternative if-expr))
  #f) ;; what do I return here?

Ответы [ 7 ]

10 голосов
/ 20 марта 2009

Согласно спецификации R6RS :

Если дает #f, а не указывается, то результат выражение не указано.

Так что, дерзай, верни все, что хочешь! Хотя я лично ожидал бы #f или '().

8 голосов
/ 20 марта 2009

Схема действительно может не возвращать значений:

   > (values)

В R5RS указана однорукая форма if для возврата неопределенного значения. Это означает, что вам решать, какое значение вернуть. Несколько Схем решили ввести определенное значение, называемое «неопределенное значение» и возвращает это значение. Другие возвращают «невидимое значение» # и записывается REPL такой, что это не печатает это.

   > (void)

Сначала можно подумать, это то же самое, что (значения), но обратите внимание на разницу:

  > (length (list (void)))
  1

  > (length (list (values)))
  error>  context expected 1 value, received 0 values
  (Here (list ...) expected 1 value, but received nothing)

Если # является частью списка, он печатается:

  > (list (void))
  (#<void>)
2 голосов
/ 27 марта 2009

Если возвращаемое значение не указано, вы можете вернуть то, что вам нравится; пользователь просто не может полагаться на то, что это значение существует, когда-либо или между реализациями.

2 голосов
/ 20 марта 2009

Ряд схем (PLT, Ikarus, Chicken) имеют тип void, который вы можете создать с помощью (void).

По крайней мере, в PLT void - это то, что вы получаете, когда делаете (когда (<1 0) #t). </p>

(PLT v4 не позволяет, если без предложения else.)

1 голос
/ 06 апреля 2009

Странные люди вернутся 'nil или '|| (пустой символ). Проблема в том, чтобы вернуть символ, который нельзя вернуть (eval (alternative if-expr)), чтобы избежать путаницы.

Если что-то может быть возвращено (eval (alternative if-expr)), и вы все еще хотите знать, попали ли вы в эту альтернативу или нет, вы должны упаковать результат с дополнительной информацией:

(if (has-alternative if-expr)
  (cons #t (eval (alternative if-expr)))
  (cons #f #f))

Таким образом, результатом является противоборствующая ячейка. Если его машина #t, значит вы что-то уклонились. Если это #f, вы этого не сделали.

1 голос
/ 20 марта 2009

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

(if (has-alternative if-expr)
  (eval (alternative if-expr)) ; make sure eval returns a list
  '())

Важное различие здесь: я не возвращаю пустой список, если не было предложения else. Пустой список означает, что не было возвращаемого значения. Если бы было одно возвращаемое значение из выражения (скажем, это было 3), вы бы имели (3) как возвращение из eval за кулисами. Аналогично, возвращение нескольких значений из выражения приведет к тому, что в списке возврата eval будет несколько элементов.

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

0 голосов
/ 20 марта 2009

Что не так с просто:

(if (has-alternative if-expr) (eval (alternative if-expr)))

...