tags:

views:

936

answers:

7

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  A: 

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.

Kyle Cronin
A: 

What is wrong with just:

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

?

J.F. Sebastian
So this just defaults to whatever the scheme interpreter's language does? Nothing wrong, unless you're trying to implement R6RS compatible Scheme on top of a non-R6RS compatible Scheme :-P
Andrey Fedorov
+2  A: 

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.)

Jay Kominek
+7  A: 

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.

Andrey Fedorov
The same is true in R5RS as well.
Matt Ellis
I prefer #f since (if '() ...) will give the #t branch (have to test with null?).
Jyaan
+2  A: 

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>)
soegaard
+1  A: 

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.

grettke
+1  A: 

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.

Fabien