On Thu, Feb 12, 2015 at 11:34 AM, Keean Schupke <[email protected]> wrote:
> On 12 February 2015 at 18:32, Jonathan S. Shapiro <[email protected]> > wrote: > >> >> One effect of this in F# is that *programmers* seem to get divided into >> two camps. One camp comes from the functional programming world. That camp >> is comfortable with the curried application syntax, and will use it >> preferentially. The other camp comes from the world of C. That camp will >> also gravitate toward what is familiar, which is to say the tuple syntax. >> The two groups will tend to build libraries in mutually incompatible style, >> which raises a concern that the user base will ultimately bifurcate. >> > > I see the problem. Tuples exist in most functional languages and I think > they are useful. I don't think I would want to get rid of them, so this > always leaves the possibility of creating different function signatures. > Any arity system would add a third syntax on top of curried and tuples, > which might just lead to further confusion and different implementations. > I think we are talking past each other again, but this time only in a small way. In brief, I don't think that any of this messes with tuple use in the slightest, and we don't need a third syntax. The rules for arity analysis in F# are [under]specified by example in section 14.10 the F# specification. They are different for functions and methods, and I am now realizing that they don't rely on tuples as heavily as I had imagined. The issue at hand, from the F# perspective, isn't so much the internal calling convention as it is the need to report a CLI type for each exported function and method. The rules are subtly different for functions and methods, in a way that I don't yet fully understand. Here's a general sketch of how this works for the *simple* cases (those not involving first-class functions). Given def f a b c ... z // formal parameters may be patterns 1. All decisions about "implementation level arity" are made based on on the *concrete* function type, after any type variables have been resolved to concrete types. 2. A function taking a single argument of type unit is implemented as an arity-0 function. 3. For all other functions, the argument patterns a..z are examined in turn, and an arity is assigned to each formal parameter pattern. If the pattern is NOT a tuple, it is assigned an arity of 1. If the pattern is a typle pattern, then it's arity is the length of the tuple. The final arity of the function in the eyes of CLI is the sum of the parameter arities. So from the CLI perspective, all of the following functions have arity 3: def f a b c = ... def f a (b, c) = ... def f (a, b, c) = ... So far so good. I think we could tighten up the specification above to make it rigorous, and that would give us a fine way to define a notion of "native arity". Note that none of the above changes how F# handles application internally, but note also that an application of the form "f (arg1, arg2)" is pretty well guaranteed to produce the behavior we want for systems codes. It may be the case for systems codes that we should simply use tuple-style arguments in all cases. There is also discussion in the F# specification that the following is inferred to be an arity-2 function at the CLI level: def f x = fun y -> ...body... They don't specify the inference rules anywhere, so I'm not sure exactly which cases are inferred in this way. Now all of this is, in a certain sense, answering the *reverse* of the question we have been asking. It is asking how F# goes about constructing the "reverse" wrapper for use by less enlightened languages. Within the language, if the function being called can be statically resolved, it is certainly possible to call the native-arity version of the function. But when the function *cannot* be statically resolved, there is a problem. Given a function parameter f with type 'a->'b->'c, and an application of that function occurring in tail position, I do not see how we can determine whether the application f a is an allocating application. This creates a very strange conundrum for effect inference, because there are cases where f a will allocate (because it is partial) while f a b will not. The overall allocation effect cannot be deduced by composing the allocation effects on the individual arrows. > One purpose of the present discussion about arity-aware function types was >> to see if we could satisfy the needs of both groups with a single surface >> syntax. >> > > Would you get rid of tuples then? I see what you are trying to do, but it > seems problematic. > No, no. I wasn't thinking about getting rid of tuples. In fact, BitC tuples are syntactic sugar on top of pairs at the moment, and I think we either need to fix that or add a Nat to the type so that we can keep track of the length. > What about named arguments (just pass a record). > Indeed. We're going to need to support optional arguments at some point as well. I don't know how to do those cleanly in the curried application style. shap
_______________________________________________ bitc-dev mailing list [email protected] http://www.coyotos.org/mailman/listinfo/bitc-dev
