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

Reply via email to