Let's do some inference. We pick up a candidate from the array, which is number. We pick up another candidate from isNeat, which is string or number. These both appear one level deep in nesting, so they're of equal priority. So we're going to pick the best common supertype from among them. That's string or number. So that's the value that we get out.
We see T is of type string or number, so X is of type string or number. Seems okay. But then you look at it for a little bit, and you're like, wait a minute, what is string doing in X? We didn't give any strings to find. Is neat can't produce strings, it can only accept strings. Find at runtime has no way to even inspect find and figure out what its argument type is, so it doesn't seem plausible that someone given an array of numbers is suddenly able to produce a string out of thin air, it doesn't make sense. If you just look at this for a while and you stare at these candidates, like earlier, you can't just look at these candidates and figure out what to do unless you have some other information.
The other information that you need to take into account here is whether the T is appearing in a covariant or contravariant position, or we might talk about this in terms of input or output positions. These Ts from the array are going into find and these values we're passing to arg from within find are coming out of find. So really we need to think about the input and output positions of the type parameters as we're collecting them. Our new algorithm is something that I can only really demonstrate with a more complicated function. I've made find take two arrays, and I've made is neat also accept Booleans. I apologize that it's a little bit longer, but we're going to call find, we're going to pass a string or number array into this first array, a number array into the second array, and then our predicate function in func here takes strings or numbers or Booleans. Let's make a little table, I'm going to condense the code sample so you can see it all on screen at once.
Let's do some inference, we're going to collect some candidates. I'm going to start at arg actually, so we're going to line up arg colon t to this string or number Boolean value, and that's going to give us our input candidate. We're going to collect from our first t array, that's a string or number, and our two gets us a number array. So we've got these list of candidates here. The thing that we seem to want to pick is string or number, so what we're going to do to get that result is we're going to treat the input positions as an upper bound on the result, and then we're going to do our regular best supertype algorithm among the other output candidates that we have. So our best output is string or number, that is below, in Type Theory terms, below this string or number or Boolean upper bound, and we'll proceed with the call as if you called find or string or number. That means that Boolean isn't showing up in X, which is definitely the right behavior. If I tweak this example a little bit, and I say isNeat only accepts numbers and then I pass in a number array and a string array, we want to issue an error here, and ideally the error that we would issue would kind of act as if you had called isNeat of A and isNeat of B. That's where the error in this program is, right? So we know from a finds signature that it is capable of passing a T from Array2 into func at the arg position, so we need to error as if you had called isNeat of A, because that's what's going on here, so let's try our algorithm out. We pick up our best output candidate from a string or a number in that array, but then we find an upper bound from isNeat, because we see n colon number in an input position, and so we stick with number, as we're inferring here.
Comments