>
>
> I think you're misunderstanding my question.

Probably.


> Also, please don't switch
> to a different example; let's stick with f. Shap chose it because it
> takes a function parameter, which is what I'm asking about.
>
> As defined, the inferred type of f is ('a -> 'a -> 'a) -> 'a -> 'a -> 'a.
>

f is a function passed a function and returning a function that takes a
single argument and returns a function taking a single argument and
returning a value, so native arity (1, 1, 1)

The first argument is a function that takes a function and returns a
function that takes a value and returns a value (1, 1).


>
> When f is called from another module, what native arity must a closure
> be in order to safely pass it to f?
>

It must have arity (1, 1)... i.e. a function which takes a single argument
and which returns a function that takes a single argument (all of type 'a).


>
> What native arity is assumed of the parameter g when compiling f?
>

(1, 1) as described above


>
> Note that the answers to the above two questions must be the same, but
> one answer must come from the compiler of a module importing f, and
> one must come from the compiler of the module defining f.
>

Here's where you lose me. We have already said all type signatures at
module boundaries should be explicit, due to the desire for a stable
interface.  In any case, in one module you would say:

export f :: ('a -> 'a -> 'a) -> 'a -> 'a -> 'a

In the other module you would say:

import f :: ('a -> 'a ->'a) -> 'a -> 'a -> 'a

If these are different it is a link-time error, not a compile time error.


>
> How does your scheme ensure that these answers will always be the same?
>

It doesn't mismatch is a link time error, but libraries can provide
'import' header files to make sure users get this right and don't have to
type it all in.


>
> And finally:
> In your scheme, what does the programmer do to control the native arity of
> g?
>

Hmm, I don't see the issue, nothing here has required local aliases so far,
but lets say I do:

import f :: ('a -> 'a -> 'a) -> 'a -> 'a -> 'a as (('a ,'a) -> 'a, 'a) -> 'a

I could then use it with a 'g' with the type ('a, 'a) -> 'a locally in this
module.


>
> >> Anyway, how is this business of using different inter-module types any
> >> better than using an arity-aware type system for compiled modules, or
> >> automatically tuplizing functions under the hood?
> >
> > Hmm, the type system is arity aware, the exact arities are encoded in the
> > types using tuples.
>
> OK, I can use that point of view. The comparison I was asking for is
> essentially the same, whether you use arities or unboxed tuples under
> the hood.
>

Well I could imagine a third syntax for arities like:

h :: {int32, int32, int32} -> {int32, int32} -> int32

but it ends up looking just like tuples, and for unboxed tuples the stack
representation would likely be the same. However if you want to allow
unboxed tuples, it might be necessary to have something like this... I need
to think about this some more as there are other reasons to make function
calling explicit verses a value. IE a unary function needs to be
distinguished in the type system from a value. In Haskell this would be
done with a datatype. Lets just say we have a datatype 'F' for function
application the above can be:

h :: int32 -> int32 -> int32 -> F (int32 -> int32 -> F int32)

This is probably my preferred solution as F captures side effects too,
leaving the function arrow '->' as a pure function. We can then make 'F' a
monad to allow composition of function application. We might call this
monad 'IO'?


>
> > With regards to automatic tupelization,  you might be coding in a
> tupelized
> > style and want to import a library of curried functions and not have to
> mix
> > styles (or import a library of tupelized functions and use them in a
> curried
> > style). Doing this automatically like F# works only one way, and seems a
> > little permissive as automatic tupelization may not work (or even be
> desired
> > in some code that relies on hoisting part of a curried application
> outside
> > of a loop for efficiency).
>
> By automatic tuplization, I mean the user can use either tuplized or
> curried functions, and the compiler will decide, based on the
> definitions, what the type should've been to best avoid closure
> allocation. Usually this means turning curried functions into tuplized
> ones. This changes their types, so both the original "surface" types
> and "tuplized" types are recorded in the compiled module. When
> importing a module, the functions still appear to the programmer to
> have their surface types, but the compiler also knows their tuplized
> types, so it can generate the correct call code.
>
> The main difference I see between what I've just described and what
> you're calling for is that you do not store the surface types in a
> compiled module, so the importer picks their own surface types to use.
>

Yes, this avoid the problem with libraries using different styles.


Keean.
_______________________________________________
bitc-dev mailing list
[email protected]
http://www.coyotos.org/mailman/listinfo/bitc-dev

Reply via email to