Am So., 14. Juni 2020 um 21:25 Uhr schrieb Wolfgang Corcoran-Mathe <xxxxxx@sigwinch.xyz>:
On 2020-06-14 18:08 +0200, Marc Nieper-Wißkirchen wrote:
> >> The `assume' is only for clarity; you can remove it without changing
> >> the semantics. The point is that `stop?' has to be called n + 1 times
> >> according to the `unfold' protocol when you generate something of
> >> length n.
> >>
> >
> > That makes sense only if `successor` is being called for its side effects
> > only.
> >
>
> Indeed. The same goes for `stop?'. If you want to implement the `unfold'
> protocol, you have to include this as well.  Otherwise, we better drop the
> unfold altogether.

Or perhaps it would be simplest to add that the result is unspecified
if the procedures passed to maybe / either-unfold have side-effects.

That would be definitely wrong. See my example with `generator-unfold' I gave to John.
 

More generally, I'd like to understand how well-specified this
"unfold protocol" is.  I'm not aware of a SRFI defining "unfoldable"
types, or general requirements of -unfold procedures; are we just

`generator-unfold' of SRFI 158 assumes the existing of some kind of `unfold' protocol.
 
following the general pattern of the unfolds of other SRFIs?  For
comparison, are there any other SRFIs which provide an unfold for
a non-sequence type, in which `successor' may not be called?  If
so, do they get the side-effecting case right?

If they don't get it right, we should correct them, not introduce the same error here.

If we're going to add phantom procedure calls in order to conform
to a protocol, it would be good to know that the protocol actually
exists!
 
There is no formal specification of what `unfold' does apart from the many examples in various SRFIs. But they all have a common behavior and if we express this behavior by using the simplest possible axioms (yielding the least surprises) we end up with that `successor' is called until `stop?' returns true on `successor' (where the result of what would be the zeroth invocation of `successor' is the seed.

(Mathematically, `unfold' is an anamorphism yielding streams and working of F-coalgebras such that a stream is the final F-coalgebra. But this description does not take side effects into account.)

Think of a new data type, which I dub super-generators. A super-generator is like a generator, but after it has yielded #<eof> once, it will continue to yield new values. So a super-generator would be a kind of flat stream of generators.

Now if `gen' is such a super-generator of 0- or 1-element generators (e.g. at least every second value yielded is #<eof>), we want to be able to write

(super-generator-unfold gen maybe-unfold)
(super-generator-unfold gen maybe-unfold)
(super-generator-unfold gen maybe-unfold)

because we can already write

(super-generator-unfold gen unfold)
(super-generator-unfold gen unfold)
(super-generator-unfold gen unfold)
(This would result in three lists of 0 or 1 elements.)