Can you return nothing from a function in Scheme?

2019-06-15 19:09发布

问题:

I'm writing a scheme interpreter, and in the case of an if statement such as:

(if (< 1 0) 'true)

Any interpreter I've tried just returns a new prompt. But when I coded this, I had an if for whether there was an alternative expression. What can I return in the if such that nothing gets printed?

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

回答1:

According to the R6RS specification:

If <test> yields #f and no <alternate> is specified, then the result of the expression is unspecified.

So go wild, return anything you want! Although #f or '() are what I, personally, would expect.



回答2:

Scheme can indeed return no values:

   > (values)

In R5RS the one-armed form of if is specified to return an unspecified value. That means it is up to you, to decide which value to return. Quite a few Schemes have chosen to introduce a specific value called "the unspecified value" and returns that value. Others return "the invisible value" #<void> and the REPL is written such that it doesn't print it.

   > (void)

At first one might think, this is the same as (values), but note the difference:

  > (length (list (void)))
  1

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

If #<void> is part of a list, it is printed:

  > (list (void))
  (#<void>)


回答3:

A number of Schemes (PLT, Ikarus, Chicken) have a void type, which you can produce with (void).

In PLT at least, void is what you get when you do (when (< 1 0) #t).

(PLT v4 doesn't allow if without an else clause.)



回答4:

When the return value is unspecified you can return what you like; the user just can't rely on that value being there, ever, or across implementations.



回答5:

First, it's OK to require if to have an else clause, if it makes it easier for you. Second, Scheme supports returning multiple values from a function, so if you were to implement the return values as a list, you could have an empty list signify that no return value was given.

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

An important distinction here: I'm not returning an empty list if there was no else clause. The empty list signifies that there was no return value. If there were one return value from an expression (say it was 3) you would have (3) as the return from the eval behind the scenes. Similarly, returning multiple values from an expression would cause the eval return list to have multiple elements.

Finally, in all practicality, you could really return anything if the condition fails and there's no else, because it would be an error in a program to attempt to capture the value of a function that doesn't return anything. As such, it would be the job of the programmer, not the language, to catch this error.



回答6:

Weird people would return 'nil or '|| (the empty symbol). The problem is to return a symbol that cannot be return by (eval (alternative if-expr)) to avoid confusion.

If anything can be returned by (eval (alternative if-expr)) and you still want to know whether you came in this alternative or not, you have to pack the result with more information :

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

Thus, the result is a cons cell. If its car is #t, then you evaled something. If it is #f, you didn't.



回答7:

What is wrong with just:

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

?



标签: lisp scheme