[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: the forward method [dynamic vs. static typing]



Neelakantan Krishnaswami <neelk@gs3106.sp.cs.cmu.edu> writes:

> Joe Marshall writes:
>> John Clements <clements@brinckerhoff.org> writes:
>> 
>> > Typically, type systems help you to construct a proof that certain
>> > errors cannot arise during evaluation.  When parts of that proof are
>> > used to alter the evaluation itself, you suddenly have a class of
>> > _runtime_ errors (or rather, "mis-behaviors") that can only be
>> > understood by examining the type proof.
>> 
>> I think that John has identified what it is that made me
>> uncomfortable with this style.  I generally think of the type system
>> as meta information.  Intertwining the control flow with the meta
>> information about the value flow not only makes it hard for humans
>> to reason about the program, it makes it hard for programs to reason
>> about it as well.
>
> But OO languages already permit this sort of computation! If
> you CPS-converted Ken's example, then all of the cases in which
> the behavior depended on the return type would turn into cases of
> argument type dispatch. Am I misunderstanding your point somehow?

You would be dispatching on the argument to FOO, not the type of the
argument to the continuation.
After CPS'ing, you'd have this:

  (foo argument (lambda (result) ....))

Now the dispatch would occur not at the point of invoking the
continuation, but rather at the point of invoking FOO!

If we were to make the dispatch explicit, foo would be defined
something like this:

(lambda (argument cont)
   (cond ((is-type? cont (int->...)) (cont (f1 arg)))
         ((is-type? cont (float->...)) (cont (f2 arg)))))

It seems weird to dispatch on the type of CONT when ultimately
we are interested not in CONT but in FOO.  Changes to FOO must take
into account all the continuations that may be supplied to FOO.

On the other hand, if we dispatch on the argument to the continuation
*after* the computation is complete, we get this:

(foo argument (lambda (result)
                (cond ((is-type? result int) ...)
                      ((is-type? result float) ...)
                        ....)))

Now FOO can be changed without regard to who or what uses the result.