shingarov / MachineArithmetic

A mathematical foundation for Smalltalk-25
MIT License
17 stars 6 forks source link

[Query] Signal structured error (NoAnswer) instead of just Error #384

Closed shingarov closed 4 days ago

janvrany commented 4 days ago

I like the idea but before I merge it, I'd like to know how where this is going to be used. The thing is, there's no NoAnswer in Smalltalk/X and the Query implementation is different. I'm not opposed changing St/X but that needs a bit of work. I'm on it already.

janvrany commented 4 days ago

Okay, adding NoAnswer to St/X seems to be quite tricky, there the default answer is nil and a lot of code depends on it (there's 38 subclasses of Query in "base image"). More thinking is needed.

shingarov commented 4 days ago

the default answer is nil and a lot of code depends on it. More thinking is needed.

After a few more hours of contemplating, I think I am starting to understand this a bit better. We are looking at another example of consequences of dynamic typing — a fundamental design choice in Smalltalk — on compositionality.

Consider the following example of the original question, due to Kleisli, seemingly unrelated to computer programming: the equation

ax = b

can be solved for x as b/a. What if a=0? We can special-case it (NB: this is happening in the control plane) and say "unless a=0"; but what if ax=b is part of a larger investigation, so a and b come from some other calculations, and x is used some later calculation? The permutations of special-cases can quickly become unmanageable. Another approach is to special-case in the data plane and adjoin NaN to the numbers (the possible values of x). So we are looking at a functor lifting numbers to maybe-numbers; and they compose because trying to operate on NaN gives you another NaN, etc. This is just Maybe with a special name ("NaN" instead of "nil").

In Haskell, many functions "F" come in two variants, "F" and "maybeF". In Smalltalk terms, "divide" would signal a ZeroDivide but "maybeDivide" would answer NaN. Or, Array>>at: would signal SubscriptOutOfBounds but Array>>maybeAt: would answer nil. This composes in the data plane, and while in Haskell it has to be explicitly plumbed through the Kleisli arrow, in Smalltalk the array member could itself be nil (e.g. if it came from a failed computation).

So for our Query, this resolves nicely the problem of "what happens if the answer does exist and is actually nil?" The question that remains, is naming consistency, but we have that problem across the board. It is in general difficult to say by just looking at a selector, whether a failure will be signaled in the control or in the data plane. In MA I have been trying to use maybeF-style names, especially when transliterating from LH, but it's not exactly parallel because in Smalltalk the Maybe is implicit (anything can be nil).

I'd like to know how where this is going to be used.

At this point in time, there are no uses of Query in the MA codebase; everything still uses the old #runReader:initialState:. This is going to change in the future but I would like to do more foundational work in this area, I want to have the Reader concept (which is — most stunningly!!! — just the left adjoint of function application, #value:) decoupled from what to key it off (Class or Symbol). So perhaps we can pospone the change in #defaultResumeValue, and limit this PR to just introducing the class NoAnswer. My use of it is in https://github.com/shingarov/MachineArithmetic/pull/384/commits/3c206296a66c0263a94b5199d54f43f9bfd55b76 (I meant to merge that later after we have concensus whether we like the NoAnswer exception at all, which we seem like it).

shingarov commented 4 days ago

adding NoAnswer to St/X seems to be quite tricky, there the default answer is nil and a lot of code depends on it (there's 38 subclasses of Query in "base image")

Oh, wait! Can you explain this again? How does changing #error: to NoAnswer signal affect anything about the default answer? We are just swapping one error class for another (which happens to be the first one's subclass), no??

shingarov commented 4 days ago

Something like 539dffa for now?