pufuwozu/roy — pull request #115 by taku0 (2012-02-22 11:24:55+00:00)
Title: Add where clause to support mutually recursive function/data definition

### Problem
Cannot define mutually recursive functions/data (in a type safe manner).

### Prerequisite
Since Roy is a effectful call-by-value language, we need distinguish let and let rec.

### Design Choice
#### Option 1: Adopting let rec
Using let rec, programs will be looks like:

let rec is_even x =
if x == 0 then
true
else
is_odd (x - 1)

and is_odd x =
if x == 0 then
false
else
is_even (x - 1)

console.log (is_even 100)

However, let rec will not match Roy's Haskell-like syntax and it will not be familiar to non-ML programmers.
(At least, I don't think it is sweet.)

#### Option 2 Adopting Haskell's where clause
Using where clause, programs will be looks like:

let main () =
console.log (is_even 100)
where
is_even x =
if x == 0 then
true
else
is_odd (x - 1)

is_odd x =
if x == 0 then
false
else
is_even (x - 1)

main ()

This looks nice to me; less noise, consist with Haskell, and top-down order.

Though we still cannot define mutually recursive functions at top-level, we might define an object creating macro:

let create_foo_module () =
create_object bar buz // => {'bar': bar, 'buz': buz}
where
bar x = ...
buz x = ...

exports.foo = create_foo_module()

I propose the option 2, adopting where clause.

### Implementation

I modified the lexer to suppress the TERMINATOR token if OUTDENT is followed by a keyword 'where'.
This is necessary since jison is a LALR(1) parser generator, so that we need know whether there is a where clause or not at OUTDENT token only with next token.

The type analysis is extended to allow mutually recursive functions.
First, assign monomorphic temporary types to all functions in a where clause.
Second, the types of each functions are inferred.
Finally, the types are qualified with forall.

Data definitions are analyzed prior to function definitions.