Closed shingarov closed 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.
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).
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??
Something like 539dffa
for now?
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.