Hi all,

Continuing, still using the syntax where f[a b c] is a call (and not an 
application), let’s define the problem. We want to translate all function 
definitions in our program from a language that allows applications to one that 
only uses function calls. This is a step towards creating assembly code, of 
course, and at one step we have to get down from the high-level language to a 
lower-level one. 

I didn’t specify notation for the type of (primitive) function calls, nor 
values of function calls. The value part is easy, all we store in memory is the 
address of the function. I’ll also use a bracket notation for their typing:

1) Term: g [a0 a1 .. aN]
2) Type: f : [A*] => R, where A* is a list of type variables (space separated), 
and R is the result type variable. The A’s and the R are general types, they 
can be also be applications.
3) Value: Address of function in memory.

For (simple) applications, I will use the:

1) Term:  g b
2) Type:  A -> B,
     Sometimes I will use A -{E}-> B, indicating the existential capture of the 
environment E.
3) Value: A tuple (a, e), where a is a function call of type a : [E A] => B, 
and e : E are the captured values.
     You can see from this that A-{E}->B is isomorphic to ([E A]=>B, E), and 
that
     A->B is equal to: exists E. A-{E}->B.

Now, we are talking about different ways of translating our (lambda-like) input 
language to one that does not have lambdas, nor applications, only let-bindings 
and function-calls. Also, as an optimization, we want to make sure that if 
there are n-applications (i.e. terms such as f a b c, and f :: [A B] -> R, then 
it is translated to f [a b] [c].

In Shapiro’s proposal, all top-level function definitions will syntactically be 
forced to produce a call, but their arguments and return value may be general 
functions. Now meeting an application `g a`, if g : [A] => R (arity = 1), and 
a: A, then g a : R. If g has more than one argument, then g : [A|Bs] => R, and 
we can type it as g a : [Bs] => R and continue. If we end up with a type [Cs] 
=> R we have specified too few arguments, and we should either error on it or 
auto-generate a function (eta-conversion), or finally keep the eta-converted 
function around in the environment, but error out if the function definition 
escapes. Too many arguments is not a problem g a : [] => R, because it will be 
type-checked against R. If R is a function (application or call) type, it’s 
good, otherwise a type-checking error.

What is not so clear to me is how to proceed when g is a value if type A -> B, 
for instance as provided as an argument to the top-level  function. Or rather, 
the main problem is that the type of a parameter can be A -> B -> C -> … -> R, 
but we want to be able to call it with a concrete function f : [A B C … ] => R. 
In this case, you would have to coerce the value f to another f’ that is an 
applicative function (i.e. the tuple (a, e) above). 

So, we need to expand on the simple applicative function values to more general 
applicative function values:

1) Term: g a0 a1 … aN
2) Type: A0 A1 … AN -> R
3) Value: A tuple (a, e) where a : [E A0 A1 .. AN] => R, e : E.

Note: I’m contradicting myself here, but yes, you *can* sensibly talk about the 
arity of a general applicative function – oops! 

We can convert a primitive function value to general applicative function 
value, by auto-generating the function 

    t : [f : [A*] => R] => (A* -> R) 
    t f = (\args . f [Nil args], Nil)       -- We might not *actually* have to 
generate this if the calling convention allows for a hidden environment 
function argument.

Unification with simple application proceeds pretty much as primitive function 
values. I haven’t proven it, but I’m pretty sure that it can work out, more 
about that later!

Thanks,

PKE

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

Reply via email to