On Mon, May 31, 2021 at 10:56 AM Marc Nieper-Wißkirchen <
[email protected]> wrote:
>
> Maybe mutability and immutability are the wrong words. What I mean here is
> that structures have some flag (which I called immutability), at least
> abstractly, which has to be set when they are arguments or return values of
> functional updaters, but which has to be cleared when they are used in
> linear update procedures. Formal conversion happens through "copy"
> procedures.
>
>
Ah, yes. It's more like sharable or not, or persistent vs transient---one
kind that can be freely passed around, and another kind that can be used at
most once.
> So, I think it is better to write
>
> ;; Functional update version
> (define my-library-function
> (lambda (input)
> (functional-update input)))
> When you want to call it with a structure that can be mutated, you would
> make the conversion explicit:
>
> (my-library-function (copy input))
>
>
Ok, I was thinking of the conversion in the other way. Yes, your example
makes sense.
And yet, what I want is that my-library-function takes advantage of
linear-updating variants. Suppose my-library-function wants to perform
operations op1, op2 and op3 over input, sequentially, each operation
returns the same type of object.
(define (my-library-funcion input)
(op3 (op2 (op1 input)))))
We know the result of op1 and op2 is only used once, so we do want to use
the linear-update version to tell the implementation "here's the
opportunity to optimize!". Such a need is real, I assume. Clojure
introduced transient data structures to do such "contained destructive
updates", precisely for the performance.
But what if we want to hide the fact that we're using it internally, and
pretend my-library-function is functional. It is especially reasonable
that we also have a path that doesn't need to update the input. Then we
need to copy input in the my-library-function.
(define (my-library-function input)
(if (we-need-operations)
(op3! (op2! (op1! (copy input))))
(non-updating-operation input)))
Then, if the caller wants to pass a transient structure, it has to call
(my-library-function (copy transient-input)), for my-library-function takes
functional structure. One copy becomes redundant.