Fri May 7 10:10:22 EDT 2010

Removing Function.hs

Basic code generation now uses Procedure.hs instead of Function.hs

Next: node naming for `compile' in test-Ai.hs

In the current bootstrapping code in test-Ai.hs all variable names are
introduced manually.  What we want to do is to take an opaque
function, and generate variable names automatically.

So, how to lift an opaque function?

Problem: the `nameShared' function needs to keep track of the nodes
that are consumed from the temp node lazy list.  Alternatively, they
can be gathered from the not-declared inputs/outputs.

Step 1: lifting [Term a] -> [Term a]

-- Lifting
lift f = proc where
    outTerms = f ins
    proc = procedure [] $ compileNodes outs tmps outTerms

*Main> lift (\(a:b:_) -> let x = (a+b) in [x*a,x*x])
out:  y0, y1
(r0) <- add (x0, x1)
(y0) <- mul (r0, x0)
(y1) <- mul (r0, r0)

Defining functions on lists however is annoying.  It's probably
possible to use tuple type info for this, and use a typeclass?

However, typeclasses do not allow type aliases..  They need tags.

Can this be wrapped in an Applicative Functor?  Maybe this should be
the point where a function is transformed into an Arrow?  Know your
abstractions...  I'm a bit lost.

This makes perfect sense:

*Main> :t lift
lift :: (Eq t, Show t) => ([Term a] -> [Term t]) -> PAbs

The question is, do we need specialized lift ops for tuples and
specialized functions?  One of the nice properties of applicative
functors is that this is all served by currying.  The PAbs data
structure however does not support higher order functions.

What about this:

-- Lifting
lift f (ins, outs) = proc where
    outTerms = f ins
    proc = procedure [] $ compileNodes outs tmps outTerms

*Main> lift (\(a:b:_) -> let x = (a+b) in [x*a,x*x]) (ins,outs)
out:  out0, out1
(tmp0) <- add (in0, in1)
(out0) <- mul (tmp0, in0)
(out1) <- mul (tmp0, tmp0)

But this is not fmap, as it's not ::  (a -> b) -> f a -> f b

This raises the question: is it better to represent compiled networks
as functions that abstract over their inputs/outputs (i.e. as Arrows)
or do we just want to compile ``only once'' at the toplevel?

Main idea here: is the Procedure ouput something we want to process,
or just a shorthand for the C/ASM/LLVM concrete syntax output?

I guess the latter, so let's not loose time thinking about this.  All
Arrow abstraaction is for higher levels.

One thing though: combinators.  You can't just convert combinators to
dataflow code by abstract interpretation: too much structure gets
lost.  Sharing is not too hard to recover, but iteration is an
entirely different story.  So yes, for combinators some kind of
morphism is probably necessary (to perform the same combinators on
Haskell vs. generated code).

The AI would be there to build kernel functions.  The combinators are
there to pipe data in / out.