Am Di., 6. Sept. 2022 um 01:45 Uhr schrieb John Cowan <[email protected]>:

>
>
>> In particular, if THUNK is a thunk, one cannot distinguish whether the
>> value of
>>
>> (make-promise THUNK)
>>
>> is meant as a thunk or as a promise in the dynamic dispatch Wolfgang
>> had in mind.
>>
>
> You can if you have access to the primitive `%true-promise` procedure.
> The only way a %true-promise could be a procedure is if the compiler can
> prove that the body of the promise is without side effects (and in practice
> running time counts as a side effect here).
>

Given the code snippet, you posted earlier, you probably mean

(define lazy-or-procedure
  (lambda (thunk)
    (cond ((%tue-promise? thunk)
           (%true-force thunk))
          ((procedure? thunk)
           (thunk))
          (else (error "not a thunk")))))

where, for simplicity, I have restricted `lazy-or-procedure` to one
argument.

But this would be wrong.  If you invoke

(lazy-or-procedure (make-promise newline))

the `newline` procedure should be returned.  Instead, the `newline`
procedure would be printed.

You could only dispatch between "true promises" and other values, but a
"true promise object" would be an implementation detail and not a specified
Scheme type.

I don't mean that ad-hoc polymorphism should be eradicated from
>> Scheme, but introducing new variants should only be done for very good
>> reasons.
>
>
> Indeed, R[57]RS has only two kinds of ad hoc polymorphism: between exact
> and inexact numbers, and between I/O-able types.
>
>
>> You mean because in a typical implementation where
>>
>> (or OBJ1 OBJ2)
>>
>> translates into something like
>>
>
>
>>
>> (let ((tmp OBJ1))
>>   (if tmp tmp OBJ2))
>>
>> only OBJ1 will be forced but not OBJ2 (if the implementation supports
>> implicit forcing)?
>>
>
> More than that.  There is no (or OBJ1 OBJ2), only (or <expr1> <expr2>),
> and there is no guarantee that <expr2> evaluates to an object.
>

Yes, writing "<expr>" instead of "OBJ" is much better.  But otherwise, I
think you say the same that I did.


> I think implicit forcing is almost all that is needed.
>>
>
> The objection to pervasive implicit forcing is that it involves a novel
> and extremely pervasive sort of polymorphism.  Thus `string-set!` becomes
> polymorphic in all three of its arguments, allowing for eight cases:
> ({string, %true-promise-of-string}, {exact integer,
> %true-promise-of-exact-integer}, {character, %true-promise-of-character}).
> A compiler may or may not be able to weed out some or all of this
> polymorphism, but you certainly can't count on it.
>

Preliminary note: I don't necessarily want to advocate implicit forcing.  A
major hurdle would be the existence of a Scheme implementation that
implements this efficiently.

Implicit forcing doesn't necessarily mean extra polymorphism (in the usual
sense), though.  An implementation (e.g. one that compiles to Haskell, say)
can be written in a way so that internally all objects look like ("true")
promises.  The dispatch would then not be according to the type (because
there would be no difference between a string and a promise of a string)
but according to whether the promise has already been forced.  This is
something every optimizing Haskell compiler needs to cope with.

Reply via email to