Am Mi., 1. Apr. 2020 um 15:56 Uhr schrieb Wolfgang Corcoran-Mathe <xxxxxx@sigwinch.xyz>:
On 2020-03-30 19:12 +0200, Marc Nieper-Wißkirchen wrote:
>How the values are stored inside the Maybe is a question internal to the
>implementation.
>
>The generalization I am proposing means that `just' takes an arbitrary
>number of values and that `maybe-ref' may an arbitrary number of values to
>`success'. `proc's and `mproc's may take more than one value and may return
>more than one value.

Some thoughts about multiple values in SRFI 189:

* Would ‘maybe-ref/default’ require as many “default” arguments as
  values contained in the “maybe” argument, or would it always return
  a single default value in the Nothing case?  The former is sort of
  reasonable assuming we could access the number of values stored in
  a Just.

The signature of `maybe-ref/default' will be `(maybe-ref/default maybe default* ...)'. It will return the values `default*...' in the Nothing case.

 
* How should multiple-value-storing Justs be compared with ‘maybe=’?
  Presumably Justs j1 and j2 are equal in the sense of maybe= iff
  j1 and j2 both return the same number of values and their values
  are element-wise equal (in the sense of the comparison procedure
  passed to maybe=).  Are there other complexities to be considered
  here?

That's reasonable, easy to grasp and simple to implement.

 
* How can ‘maybe-join’ handle Justs with multiple Just payloads?
  e.g. would (maybe-join (just (just 1) (just 2))) return a value
  equivalent to (just 1 2), or something else?

As stated, `maybe-join' is the monadic join. Given a monad T, in particular, an endofunctor of some category C, the join operation is the monadic product T^2 => T, a natural transformation, that is for each object c of C a morphism T(T(c)) -> T(c) that is natural in c. In the case of Haskell, the category C is the category of all Haskell types.  In the case of Scheme, we have no static typing but procedures and continuations take arbitrary numbers of values.  Thus, in the case of Scheme, the category C is the category whose objects are natural numbers n whose morphisms m -> n are Scheme procedures taking m values and returning n values.

I am writing this so that we get the correct semantics and really implement a monad.  In this setting, the Maybe monad is an endofunctor T, that object-wise maps each object n of C to 1 (because a `(just x* ...)' is just one value.  The join operation is a procedure T(T(n)) -> T(n), for each n, that is a procedure T(1) -> T(n).  Thus, in case the `maybe' argument of `maybe-join' is a Just, it is an error if its payload is not a single Maybe value.  Therefore, the definition of `maybe-join' won't change and `(maybe-join (just (just 1) (just 2)))' is an error.

* Should ‘maybe-contains?’, ‘maybe-filter’, and ‘maybe-remove’
  traverse the values of a multiple-value Just?  That is, could we
  expect results like the following:

  (maybe-contains? eqv? (just 'a 'b) 'b)  ; => #t

The signature of `maybe-contains?' will be `(maybe-contains? equal maybe obj* ...)'. It is equivalent to `(maybe= equal maybe (just obj* ...))'.
 

  (maybe-filter boolean? (just 'a #t))    ; => (just 'a)

No, that would be the wrong semantics. The `pred' argument of `maybe-filter' will take as many values as there are stored in the Maybe.
 

  If these semantics were adopted, would it be consistent for
  ‘maybe-length’ to give the number of values contained in a Just?

`maybe-length' should still return `1' or `0' as Maybes will be sequences of length `1' or `0', whose entries can consist of multiple values. (Apart from that any other definition wouldn't catch the correct semantics, the payload of a Just can contain no values (`(join)'), and returning the number of stored values would cause confusion with Nothing.)

 
* Would Either also allow multiple values?  (Presumably.)

Yes, of course.  Like Maybe, we want either to fit into a general monadic framework for Scheme as well.
 
It seems that it would be necessary for a Just to store the number
of values it contains along with the values themselves.  We could
expose the number of values contained in a Just, e.g. with
‘maybe-length’.

Implementation-wise, in a portable implementation, I would use a list to store the values. If an implementation has flexible arrays/records, I would use them. From a mathematical point of view, a procedure like `maybe-length' would be a type-inspection facility and doesn't fit into the monadic framework. I wouldn't add it to this SRFI (as much as we have no procedures inspecting the arity of procedures).
 
All in all, this is interesting, but seems to me to be a substantial
increase in complexity.  The possible semantics of some of these
procedures (especially ‘maybe=’ and the sequence operations) in the
presence of multiple-value Justs all seem pretty awkward.  It’s quite
possible that I’ve missed a better approach, though.

After the clarification above, could you say what still looks awkward to you?

As has been discussed in another thread, this SRFI 189 doesn't give any tool to the Scheme programmer with which they can solve a problem they wouldn't be able to solve with the already existing solutions of communicating failures (what John called "conventions" in the other thread).  But this is not the main point of this SRFI, I think.  As much as Scheme is a language to solve practical problems, it is also a language to communicate algorithms and meanings of computer programs.  Already for that, having a Maybe monad in Scheme is a great thing.  But for that, we really have to take care and work hard to get the right and the full semantics of a monad.

Best,

Marc

 

Regards,

--
Wolfgang Corcoran-Mathe  <xxxxxx@sigwinch.xyz>

"Conquering the galaxy is what bacteria with spaceships would
do--knowing no better, having no choice." --Greg Egan, _Disapora_