With Chez Scheme version 9.5.5, consider the two examples of cond
:
(cond #t (else 2))
(cond (> 2 1) (else 2))
The first expression evaluates to #t
, while the second expression evaluates to 1
.
It seems that the first expression is first expanded to (cond (#t #t) (else 2))
, while the second expression is expanded to (cond ((> 2 1) 1) (else 2))
before evaluation.
My question is: Since the value of expression (> 2 1)
is #t
, It is counter-intuitive to me that the two cond
expressions have different values. Are there good reasons to define cond
in such a way?
Edit: I tried the two expressions with GNU Guile 3.0.1:
(cond #t (else 2))
triggers an erorr, which says "cond: invalid clause in subform #t of (cond #t (else 2)".(cond (> 2 1) (else 2))
evaluates to 1
as with Chez Scheme 9.5.5.(cond (#t) (else 2))
evaluates to #t
.Edit2: With CHICKEN Scheme 5.1.0:
(cond #t (else 2))
triggers an erorr, which says "during expansion of (cond ...) - in `cond' - not a proper list: #t".(cond (> 2 1) (else 2))
evaluates to 1
as with Chez Scheme and GNU Guile.(cond (#t) (else 2))
evaluates to #t
but with a warning which says "Warning: clause following #t' clause in
cond': (else 2)".The first expression raises an exception in Chez 9.5.4, which is the most recent release:
> (cond #t (else 2))
Exception: invalid syntax (cond #t (else 2))
Type (debug) to enter the debugger.
I'm not sure why 9.5.5 would be different in that regard; if true, this probably points to a change in the underlying implementation of cond
in 9.5.5.
In any case, the cond
form takes one or more <cond clause>
arguments, and an optional else
clause, where a <cond clause>
must be of the form (<test> <expression1> ...)
; i.e., a <cond clause>
must be a parenthesized expression containing one test form and zero or more expressions. Each <cond clause>
is evaluated in order until a <test>
evaluates to true, after which the subsequent expressions are evaluated in order, and the value of the final expression is returned. When there are no subsequent expressions in a true <cond clause>
, the value of <test>
is returned.
The expression (cond #t (else 2))
violates this (because the first <cond clause>
is malformed) and should probably raise a syntax error, which 9.5.4 does. If 9.5.5 does not raise a syntax error in this case, a bug report should probably be filed with the maintainers. Note again that 9.5.5 is not a released version of Chez Scheme, though.
This was already stated above, but I'll repeat here: when a <test>
expression evaluates to true, and there are no subsequent expressions in the <cond clause>
, the clause evaluates to the value of <test>
. So this is expected to work according to R6RS, and it works as expected in 9.5.4:
> (cond (#t) (else 2))
#t
This would also be the correct way to express the second expression in the OP question. Here I have modified the else
clause to return 3
to make it a bit more clear which branch is evaluated:
> (cond ((> 2 1)) (else 3))
#t
> (cond ((> 1 2)) (else 3))
3
To be clear: the first <cond clause>
in the first expression above is ((> 2 1))
, which contains the <test>
(> 2 1)
. This test evaluates to #t
, and since there are no subsequent expressions in this clause, the clause returns #t
. The second expression has ((> 1 2))
as its <cond clause>
, with the <test>
(> 1 2)
. This test evaluates to #f
, so evaluation proceeds to the next <cond clause>
, (else 3)
, which returns 3
.
The unaltered second expression posted in the question behaves the same way in 9.5.4 as reported by OP for 9.5.5. This behavior is exactly as R6RS specifies it should be:
> (cond (> 2 1) (else 2))
1
The first <cond clause>
here is the form (> 2 1)
, where >
is the <test>
, and 2
and 1
are <expression1>
and <expression2>
. Now, if <test>
evaluates to true, then the subsequent expressions are evaluated, and the value of the final expression is returned.
So, with (cond (> 2 1) (else 2))
, the first <cond clause>
is (> 2 1)
, with the <test>
being the expression >
, which evaluates to a procedure, which is not #f
and thus a true value. Then the subsequent expressions 2
and 1
are evaluated in turn, and the value of the final expression is 1
, which is then returned.
Note that the form (> 2 1)
is not evaluated as a <test>
here; the form >
alone is evaluated as a <test>
. Further, (< 2 1)
should behave identically to (> 2 1)
in this case. In fact, any similar form will behave identically to this, so long as the first element does not evaluate to #f
:
> (cond (> 2 1) (else 3))
1
> (cond (< 2 1) (else 3))
1
> (cond ('any-truthy-thing 2 1) (else 3))
1
A few days after I posted this answer the new version of Chez was released. Note that OP was working with 9.5.5, which was never a release version (presumably OP built 9.5.5 from source). The new release is 9.5.6. I did not build 9.5.5 from source to test any of this; I used the current release at the time, which was 9.5.4. I have now updated to 9.5.6 on my main machine, and both 9.5.4 and 9.5.6 have identical behavior for the expressions OP asked about. The first OP expression was (cond #t (else 2))
, which OP found to evaluate to #t
. Chez should not return #t
in this case, but is required to raise a syntax error, as explained in my answer above. An issue was raised with the maintainers for 9.5.5, but the problem could not be reproduced. The second expression was (cond (> 2 1) (else 2))
; this expression was treated correctly by 9.5.4, OP's 9.5.5, and now also by the current 9.5.6 release.