program

type Int = int 32;
type Float = float 32;

sum :: (Int -> Float) -> Int -> Int -> Float -> Float;
sum f i n acc = if i < n 
  then sum f (i+1) n (f i + acc) 
  else acc;


fac :: Int -> Int;
fac 1 = 1;
fac x = x * fac (x-1);

ifac :: Int -> Float;
ifac x = 1.0 / ((fac x) as Float);

e :: Int -> Float;
e n = sum ifac 1 n 0.0;

-- {- 
-- 1

expression e 5;
-- -}



{- 
--2

box gen
  in  (s::Int)
  out (o::Int, s'::Int)
match
  (x) -> (x, x+1);

box work
 in  (i::Int)
 out (o::string)
match
 (x) -> ((e x, '\n') as string);

stream output to "std_out";

wire gen (gen.s' initially 1) (work.i, gen.s);
wire work (gen.o) (output);
-- -}


{-
--3

box sum
  in  (i::Int, s::Int, t::Float)
  out (o::Float, s'::Int, t'::Float)
match
  (*, 0, acc) -> (acc, *,   *)
| (*, n, acc) -> (*,   n-1, acc + ifac n)
| (n, *, *)   -> (*,   n,   0.0);

box gen
  in  (s::Int)
  out (o::Int, s'::Int)
match
  (x) -> (x, x+1);

box work
  in  (i::Int, j::Float)
  out (o::string, p::Int)
match
  (*,y) -> ((y, '\n') as string, *)
| (x,*) -> (*, x);

wire gen (gen.s' initially 1) (work.i, gen.s);
wire sum (work.p, sum.s', sum.t') (work.j, sum.s, sum.t);
wire work (gen.o, sum.o) (output, sum.i);

stream output to "std_out";
-- -}


{-
--4
-- @TODO - broken

box fac
  in  (i::Int, s::Int, t::Int)
  out (o::Int, s'::Int, t'::Int)
match
  (*, 1, acc) -> (acc, *,   *)
| (*, n, acc) -> (*,   n-1, n*acc)
| (n, *, *)   -> (*,   n  , 1);

 
box sum
  in  (i::Int, s::Int, t::Float, u::(Int,Float), j::Int)
  out (o::Float, s'::Int, t'::Float, u'::(Int,Float), p::Int)
match
  (*, 0, acc, *,        *) -> (acc, *,   *,                        *,        *)
| (*, n, acc, *,        *) -> (*,   *,   *,                        (n, acc), n)
| (*, *, *,   (n, acc), f) -> (*,   n-1, acc + 1.0 / (f as Float), *,        *)
| (n, *, *,   *,        *) -> (*,   n,   0.0,                      *,        *);

box gen
  in  (s::Int)
  out (o::Int, s'::Int)
match
  (x) -> (x, x+1);

box work
  in  (i::Int, j::Float)
  out (o::string, p::Int)
match
  (*,y) -> ((y, '\n') as string, *)
| (x,*) -> (*, x);

wire gen (gen.s' initially 1) (work.i, gen.s);
wire sum (work.p, sum.s', sum.t', sum.u', fac.o) (work.j, sum.s, sum.t, sum.u, fac.i);
wire work (gen.o, sum.o) (output, sum.i);
wire fac (sum.p, fac.s', fac.t') (sum.j, fac.s, fac.t);


stream output to "std_out";
-- -}
