INSTRUCTIONS
============

To build this program, you need Ocaml 3.11 or higher, Lablgtk2, and a
Unix-alike environment. (I used Cygwin, so Linux and Mac OSX should
also work fine.)

WIN32 Notes: To install Lablgtk2 on Windows, you need to download 
binary Lablgtk2 for Windows from 

   http://wwwfun.kurims.kyoto-u.ac.jp/soft/lsl/lablgtk.html

and use the *MingW* native Ocaml installation. (The MSVC version
doesn't work, because the Lablgtk2 binary was compiled with mingw
gcc. 

Cygwin comes with an Ocaml/Lablgtk pair, of which the lablgtk2
distribution is broken. You can, however, use Cygwin's Ocaml and
(X-based) GTK, and compile Lablgtk yourself.

The command:

  $ make clean; make

will build all the libraries and then construct a new Ocaml toplevel
called 'frpcaml.exe'. This toplevel automatically loads the dataflow
library, and the syntax extension that makes using it tolerable.

So, now you can engage in sessions like 

  # let succ n = n + 1;;
  - : int -> int

  # let t = Dsl.run(do U(let succ : D(int) -> D(int) = fun x -> [succ] x in
                         let rec ints (n : D(int)) :  S(D(int)) =
                           cons(n, ints(succ n))
                         in
                         ints [0]))
  - : val t : unit -> int 
  
  # t();;
  - : int = 0
  # t();;
  - : int = 1
  # t();;
  - : int = 2


If you just want to use the library directly, then 'make frp.cma' will
build a library called frp.cma, which contains the combinatory
interface. The dsl.mli file contains the type declarations for this
library. (Likewise, the underlying dataflow library's interface is
dataflow.mli.)

Examples can be found in "example.ml". 

If you are curious what these little programs desugar to, then you can
use the command:

 $ camlp4of pa_metric.cma <filename>

will print out a desugared version. Warning: even tiny expressions
desugar to huge combinator terms.

SYNTAX
======

The programming language is basically the lambda calculus of our
paper, using a subset of ML syntax.

The syntax of types is given by the following grammar: 

type ::= 
    [ [ type -> type            
      | type * type ]
    | [ one               
      | S ( type )    
      | Next ( type )
      | D ( ML-type ) 
      | Gui ( type )
      | ( type ) ]
    ]

Here, we use nesting to indicate precedence levels. The S is 
the stream type constructor, and Next is the next modality (written
with a bullet in the paper). D() are the discrete types, and all Ocaml 
types can be embedded within.

The Gui(A) type is the monadic type of gui-constructing expressions. 

The syntax of terms is given by:

  expr ::= 
           [ binders
           [ fun pat+ -> expr 
	   | let rec var : type = expr in expr 
	   | let rec var pat : S ( type ) = iter in expr 
	   | let gui pat = expr in expr 
           | let pat = expr in expr 
           ] 
         | annotation
           [ expr :  type ]
         | application
           [ head expr 
	   | tail expr 
           | await expr 
           | next expr 
	   | fst expr 
	   | snd expr 
	   | return expr 
           | cons (  expr , expr ) 
	   | map ( expr , expr ) 
	   | zip ( expr , expr ) 
           | expr expr 
           ]
         | atomic
           [ var 
           |  ( ) 
           |  ( expr ) 
           |  ( expr , expr ) 
           |  [ ocaml-expr ] 
	   |  { ocaml-expr } 
           ]
         ]

  iter ::=
    [ [ cons ( expr , var expr ) 
      | let pat = expr in iter
      ]
    ]

  pat ::=
    [ [ ( ) 
      | ( pat , pat ) 
      | ( pat ) 
      | var : type 
      | var
      ]
    ]

The [e] lets you embed an ML type as a discrete value within the DSL. 
Really, there's a whole second adjunction between (idealized)
ML and the ultrametric category, which I hide under a set of coercions
from ML into ultrametric functions and products. 

There's also an {-} special form, which takes ML values representing
closed morphisms (i.e., elements of Hom(one, A)) and embeds them as
constant expressions in the language. You need to give it a type
annotation to tell the typechecker what type this ML value has -- see
the examples.ml file for usage.

Recursive values are defined with a letrec form. The form let rec x :
tp = e in e' defines a recursive value of type tp. Streams are handled
specially and are efficient, but recursive functions often leak memory as a
consequence of our implementation strategy. So we also have a special purpose
letrec for tail-corecursive functions, which is efficient:

  let rec f(x : tp) : S(tp') = 
     let y = ... in 
     cons(e1, f(e2))
  in
  ...

This basically compiles into an unfold, which we can handle efficiently. 
We're currently looking at denotational models of polytime computation
to see if we can't either do better or prove we can't do better. 

GUI expressions are monadic (within the ultrametric language itself,
so it's a monad in our DSL, not in ML). The return e form is the unit
of the monad, and the let gui(x) = e in e' form is the monadic binding
operation. There are various operations in the Dsl module's API to
construct buttons and labels and so on -- again, see the examples.ml
file for, well, examples.

The typing judgement is a simple bidirectional typechecker. It is
simultaneously surprisingly clever about not needing useless
annotations, and surprisingly hapless. In general, stick type
annotations around any subexpression for which the typechecker
complains it cannot synthesize a type, and you should be fine.

Also, the typechecking is simply-typed. This is a consequence of the
weakness of ML's typing -- we can only embed simple types in ML using
the phantom type trick. So we can't write (for example) the
polymorphic map function within the DSL. (We can quantify over
embedded ML types, of course.)


