Subject: Re: [bug#76485] [PATCH] gexp: ‘with-parameters’ properly handles‘%graft?’.

From: Ludovic Courtès <[email-masked]>
Date: Thu, 27 Feb 2025 10:38:52 +0100

Hi David,

David Elsing <[email-masked]> skribis:

>> +  ;; XXX: Non-local exits can leave PARAMETERS set to VALUES.
>> +  (mlet* %store-monad ((old-values
>> +                        (return (map set-value parameters values)))
>> +                       (result (thunk)))
>> +    (mbegin %store-monad
>> +      (return (map set-value parameters old-values)) ;restore old values
>> +      (return result))))
>
> However, I'm not convinced it is meaningful to set the parameters for a
> general monad, e.g. for the identity monad or the list monad, there is
> no way for the parameters to have an effect, only during the evaluation
> of a function.

Still, ‘mparameterized’ does the right thing, whether you’re using
‘%state-monad’ or ‘%identity-monad’:

--8<---------------cut here---------------start------------->8---
scheme@(guile-user)> ,optimize (mparameterize %identity-monad ((current-output-port (%make-void-port "w")))
				 (mlet* %identity-monad ((x (return 2))
							 (y (return 3))
						         (z (return (+ x y))))
				   (return (* z 2))))
$26 = (let ((old-value (current-output-port)))
        (current-output-port (%make-void-port "w"))
        (let ((mvalue 10)) (current-output-port old-value) mvalue))
scheme@(guile-user)> ,optimize (mparameterize %state-monad ((current-output-port (%make-void-port "w")))
				 (mlet* %state-monad ((x (return 2))
						      (y (return 3))
						      (z (return (+ x y))))
				   (return (* z 2))))
$27 = (let* ((old-value (current-output-port))
             (mvalue
              (let ((value (current-output-port (%make-void-port "w"))))
                (lambda (state) (values value state)))))
        (lambda (state)
          (call-with-values
           (lambda () (mvalue state))
           (lambda (value state)
             ((begin
                (current-output-port old-value)
                (lambda (state) (values 10 state)))
              state)))))
--8<---------------cut here---------------end--------------->8---

That is, no matter what, it changes the value of the parameters before
evaluation of the body happens (whether or not it’s delayed) and changes
it back after.

> Instead, I would suggest to only do this for the state monad, as the
> parameters have an effect during the function application of the
> monadic value to the state. The same applies to `mparameterized' in
> (guix monads). Do you think that makes sense?

Yes, though it would be nice to have a variant of ‘parameterize’ “that
works for monad”, that was the intent of ‘mparameterize’.

Because of that, I have a preference for ‘mparameterize’ rather than
‘state-parameterize’ or any other specific variant.

WDYT?

> This allows for the use of `with-fluids*', keeping the parameterization
> local. In the following message is a patch with the changes, which
> (apart from the issue below) appears to work.

Yes, that’s because ‘with-fluids*’ is implemented in C, which makes it a
“continuation barrier” (continuations that contain C stack frames cannot
be resumed).  It’s a limitation of the current implementation rather
than a bug, strictly speaking.  :-)

Thanks,
Ludo’.