[gambit-list] Is there a way to return "nothing"?

Christian Jaeger christian at pflanze.mine.nu
Sun Apr 29 14:46:39 EDT 2007


dillo gimp wrote:
> Is it a good idea hacking the interpreter to automatically ignore all <#void>?

No, I don't think so.

> I don't know if <#void> servers any purpose...

It's #!void, btw (with exclamation mark).

It's a value that you can't rely on. The "unspecified" value. I consider
it an important sign of code which doesn't return a value when it
should, like forgetting the else branch in an (if foo "bar") or similar.
Using it for the purpose of specifying something (namely "no value")
would be wrong since that would be a valid usage then, not a bug anymore.

You should use '() for that purpose and write the receiver so that he
knows to expect a list.

You know, even perl differentiates between splicing mode and sublist
mode: you add [ ] around a list (or take a reference of an array
variable) to make it explicitely an array. There's no way around being
explicit or ambiguities will arise. Only in places where certain
ambiguity doesn't matter you can get away without (like in my
flat-string-append or SXML examples).

The question is rather which syntax you want to use for the purpose of
differentiating between the two modi.

> "length" actually counts <#void> as well.

Sure, it's an element in the list (holding a "buggy" value, so to say,
you want to see that for debugging!).

> There are legitmate reason for returning nothing, either because
> the caller has been written yet, or that it would be ugly to push the
> logic to the caller.

Usually you choose #f for saying "no object" (kind of like the C null
pointer). But if you want to make #f part of the range of valid objects,
you should specify your iterface to return a list (maybe of 0 or 1 values).

You know, other lisps only had nil. Scheme went so far as to make two
values out of the one: #f for boolean false or "none" in "scalar
context", and '() for "none" in list context. Separating #f into yet
another two values probably won't do much good, especially since it
would make code like
  (or (maybe-x)
      (maybe-y)
      (maybe-z))
more complicated. It's nice to be able to interpret the "missing value"
as false. You can use boolean operators for handling branches on missing
values.

But nobody told that the missing value should automatically vanish in
list context. Even perl doesn't do that, if you return undef, its still
inserted into the output. Only if you return (), it vanishes. Same thing
with Scheme, you return '() into a context which expects a list, and
everything is fine.

A solution which is being used for cases where one wants to be sure that
the user checks for the missing value (e.g. throw an exception if he
doesn't seem to be prepared for the check), is to expect him to give a
function a special value which is then returned as "nothing". See
Gambit's table-ref as example.

And there's the solution of using "manual CPS style" and explicitely
pass separate continuations that the function should call depending on
the outcome.

(define (frob val success failure)
  ....
  (if was-successful
      (success result)
      (failure)))

> I'm doing polynomial addition and it's possible the term could be eliminated:
> If I push the logic to the caller, the code looks ugly.
> Besides, the code hasn't been written yet.
> It would be better for the language to support it, instead of people
> each hacking a different interpreter...
> 
> (define (TaddT x y)
>   (if (equal? (cadr x) (cadr y))
>       (if (not (= (+ (car x) (car y)) 0))
>           (list (list (+ (car x) (car y)) (cadr x)))
>           '()
>       )
>       '()
>   )
> )

Could you use #f for the purpose? Maybe your case is special in that you
 could safely return #f, but insert the value into list context. What about:

(define (TaddT x y)
   (and (equal? (cadr x) (cadr y))
        (not (= (+ (car x) (car y)) 0))
        (list (+ (car x) (car y)) (cadr x))))

(define (list* . args)
   (filter values args))

>         `(aaa ,@(TaddT '(2 (1 2 3))  '(3 (4 5 6))) aaa)

       (list* 'aaa (TaddT '(2 (1 2 3)) '(3 (4 5 6))) 'aaa)

But maybe it would really be nicer to write it using the fold approach?
(Building results by prepending them onto a list of results can in some
way really make for code that's nice and logical. You're folding your
tree together to an output list.) I don't have the time to check out
what you're doing exactly.

Christian.

(hoping indentation is being preserved this time)



More information about the Gambit-list mailing list