Just a quick further note, this also solves the library problem as I can also also:
import add :: int32 -> int32 -> int32 as (int32, int32) -> int32 If I want, so I don't need to worry how the library author did things. In this way I can bring the coding styles of libraries authored by multiple different people into conformity with how I want to code. Keean. On 13 February 2015 at 20:04, Keean Schupke <[email protected]> wrote: > I would rather specify this at the module level, rather than have things I > have no control of happening. The function user should be able to control > how they want it to apply in their module, without affecting anything else > so: > > import 'C' add(int32, int32) -> int32 as int32 -> int32 -> int32 > > So the compiler knows the native calling convention and how I intend it to > type check. > > I don't like the way F# does this implicitly. > > I think I would want to control heap allocation via effects, so if I put > an effect constraint on a function "no heap allocation" then the function > (or module) will fail to compile if I have used any constructs that force a > heap allocation. Of course the compiler should try and remove the heap > allocation by specialisation, inlining, partial evaluation, and AST > rewriting before giving up. > > > Keean. > > > On 13 February 2015 at 19:48, Jonathan S. Shapiro <[email protected]> > wrote: > >> 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 >> >> >
_______________________________________________ bitc-dev mailing list [email protected] http://www.coyotos.org/mailman/listinfo/bitc-dev
