Alternative topological sorting implementation Maxime Devos (13 Apr 2023 15:12 UTC)
Re: Alternative topological sorting implementation Marc Nieper-Wißkirchen (13 Apr 2023 15:29 UTC)
Re: Alternative topological sorting implementation Maxime Devos (13 Apr 2023 16:00 UTC)
Re: Alternative topological sorting implementation Marc Nieper-Wißkirchen (13 Apr 2023 20:18 UTC)
Re: Alternative topological sorting implementation Marc Nieper-Wißkirchen (13 Apr 2023 20:35 UTC)
Re: Alternative topological sorting implementation Maxime Devos (17 Apr 2023 21:33 UTC)
Re: Alternative topological sorting implementation Marc Nieper-Wißkirchen (18 Apr 2023 05:58 UTC)
Re: Alternative topological sorting implementation Maxime Devos (18 Apr 2023 07:53 UTC)
Re: Alternative topological sorting implementation Maxime Devos (17 Apr 2023 21:13 UTC)

Re: Alternative topological sorting implementation Maxime Devos 18 Apr 2023 07:53 UTC
Op 18-04-2023 om 07:57 schreef Marc Nieper-Wißkirchen:
> Am Mo., 17. Apr. 2023 um 23:32 Uhr schrieb Maxime Devos
> <xxxxxx@telenet.be>:
>>
>>
>>
>> Op 13-04-2023 om 22:34 schreef Marc Nieper-Wißkirchen:
>>> PPS Maybe I should have better pointed to what I called liquids here:
>>> https://github.com/mnieper/scheme-libraries#liquids.  Although one can
>>> change them with set!, there is no mutation of a location in the store
>>> happening, > but just some delimited continuation wizardy.  The thing I
>>> like about liquids is that they abstract away from the rather
>>> low-level continuation primitives.
>>   >
>>> So you can just set! visiting and set! visited and are still doing
>>> pure programming. :)  Liquids can be easily implemented in Guile.  Do
>>> you think they would make a good addition?
>>
>> AFAICT, these are just parameter objects, except for 'change them with
>> liquid-set!, but purely!'.  I haven't ever seen a use of doing a
>> mutation of a parameter that couldn't be improved by doing a
>> 'parameterize' (cf. let-liquid') (or not using parameters at all) instead.
>
> Replacing the mutation of a parameter (which has indefinite extent)
> with parameterize (which has dynamic extent) is generally not possible

I am not talking about whether something it's possible in general, I am
only taking about situations encountered in practice.

> without a non-local program transformation (which may not be
> possible).

Well, yes, sometimes to improve a program, you need to do some non-local
transformation.  It's also called "code refactoring" sometimes.  I don't
see an issue here.  And yes, sometimes you can't replace parameter
mutation by parameterize, but there exist other replacements too; there
is more to Scheme than only parameters.

>  As an example, consider you have a for-each (higher-order)
> procedure modeling some sequence and want to return a fold procedure
> for it.  You would have to use the liquids' set! for it.

No.  As I understand it, this 'for-each -> fold' transformation only
uses liquid-set!, not let-liquid -- it only uses mutation of liquids,
not parametrize of liquids.  As such, this transformation only needs a
pure implementation of a SRFI-111 box, perhaps the state implementation
at
<https://github.com/mnieper/scheme-libraries/blob/9f5d134b5ff487244c9b9a1d983ce2d97a797851/test-effect.scm#L50>.

This transformation could then be improved by using the easier to
understand 'state' instead of the more powerful and more complicated
'liquids'.

That said, I only know how to implement 'map' in terms of 'for-each';
'fold' is something I haven't tried before to implement simultaneously
imperatively and purely; perhaps the equivalent of SRFI-111 boxes is
insufficient.

>> As such, I would answer your question with 'no'.  (Of course, perhaps
>> there is some application where mutating a parameter would be a really
>> good fit instead.)
>>
>> Even then, I disagree with "and are still doing pure programming." -- if
>> you implement a pure implementation (e.g. in Scheme without set! stuff)
>> of an impure language (e.g. Scheme with set! stuff), and then use your
>> pure implementation to the impure language, then you're doing impure
>> programming -- it's the language that matters, not the implementation of
>> the language (*).
>
> I get your point, but liquids don't reimplement Scheme's `set!`.
> Scheme's `set!' modifies locations in the store (of the formal
> semantics of Scheme), and this modification can be observed.  This is
> not true for the liquid-version of `set!'.

The liquid-version implement its own equivalent of the store, and you
sure can observe mutations of that:

(stuff to install liquid effect stuff
   ;; I'm using the parameter API instead of the liquid API
   ;; because that's what I'm familiar here.
   (let ((p (make-parameter 'old)))
     (p 'stuff) ; also, here we use the liquid reimplementation of 'set!'
     (observe (p)))) ; 'stuff is observed, not 'old'!

That this store is not ‘on the same level’ (so to say) as the store
described in the Scheme specifications, and that locations (i.e.
liquids) + mutations (i.e. liquid-set!) are implemented in a pure manner
by the effect handler is irrelevant:

‘it's the language that matters, not the implementation of the language’

-- from the POV of the stuff inside the effect handler, the store and
kind of locations that matters is the store implemented by liquid-set!,
not the store implemented by the Scheme implementation (e.g. Racket,
Guile, ...) itself.

> Of course, one has to
> agree upon what one means by purity (where there is no absolute
> definition).  The definition I use here is exactly about whether
> previously allocated locations in the store are modified (and so that
> this mutation is observable).

For the relevant store, yes.  If mutation is unobservable, then it's
useless -- the point of mutation is being observable; if mutation is
unobservable, you could just not mutate instead.

>> (*) There might be some exceptions like if e.g. you use the purity of
>> the host language to implement, say, time travel, for the implemented
>> impure language, but usually I find the "but the mutation is implemented
>> purely!!!" a pointless distinction (except for neatness points).
>
> You can employ a much stricter definition of purity (let us call it
> "strict-purity") for now.  Neither the liquid version of `set!', nor
> the use of parameters (even without mutating them), nor the use
> (delimited) continuation, nor the procedure `cons' are strictly pure.
> In particular, your solution of the topological sort is also not
> strictly pure.
>
> For many reasonings, this strict pureness is not helpful, though.  See
> my for-each/fold example from above, where you need pureness in the
> first sense but where questions of strict pureness are not helpful.

Well, yes, it's not helpful.  That's why I'm not using that notion.

My personal definition: 'pure = no mutation, and it doesn't matter how
'purely' you implement mutation' (I know there exist other stricter
definitions like "no effects").  And yes, then my implementation isn't
pure, but as I wrote before:

‘and I wanted to avoid 'set!', but perhaps I'm just implementing 'set!'
in terms of delimited continuations here.’

I never claimed that my implementation is pure.

(I also never claimed that purity is required or always a good thing TBC.)

Greetings,
Maxime.