Wed Dec 28 11:01:46 EST 2011

Monadic anyway..

The problem is that, while it's possible to declare structs in
argument lists, it's not possible to declare them twice.  It might be
best to just gather declarations in a monad side channel and spit them
out later.

Where to add this?  Toplevel definitions?  There seems to be no need
to push the monad structure down to the statement/expression level.

It might be as simple as a Writer monad.  Generate in first pass,
duplicates can be removed later.

Or, a state monad that takes a list of toplevel expressions.

Let's decide the form later and start witht he identity monad.

So... everything seems to be concentrated in termTopDef, and a Monad
doesn't seem to be necessary because juggling the side-channel of type
definitions is something that can probably be managed.

However, it might be a good exercise to use some of the standard
Writer / State monads.

Actually this turns out to be quite simple.  If the hidden state is a
Monoid, then it's OK to just use MonadWriter class: execWriter, tell.

So... I'm trying to only add structs that aren't there yet but it
doesn't seem to work:

  -- Query the type tags.
  getDict = do 
    ((), dict) <- listen $ return ()
    return dict 
  getTag typ = do
    dict <- getDict
    return $ find (\(tag,_) -> tag == typ) dict

  -- Save struct definitions of AStruct tags that appear in function
  -- arguments, so canonical struct names can be used in the function
  -- bodies.
  structDef var@(Var (Type (AStruct sub) _) _) = do
    typ <- return $ Type (AStruct sub) 0
    tag <- getTag typ
    case tag of 
      Just _ -> 
        tell [] 
      Nothing -> 
        tell [(typ, CDeclExt (CDecl [(cTypeSub typ)] [] ()))]
  structDef var = 
    tell []

I think "listen" doesn't really work the way I think it does.  If
there are subcomputations, are they actually executed in sequence, or
are they executed separately with results concatenated?  If that's the
case then "listen" only gives part of the answer.

From [1]:

  instance (Monoid w) => MonadWriter w (Writer w) where
          tell   w = Writer ((), w)
          listen m = Writer $ let (a, w) = runWriter m in ((a, w), w)
          pass   m = Writer $ let ((a, f), w) = runWriter m in (a, f w)

What IS a value of m a?  It is a Writer datastructure so indeed this
is only part of what's going on.

So.. I used Control.Monad.State combined with Data.Map and a hackish
way to generate the Ord instance for Map:

  type Dict    = Data.Map.Map TypeName (CExternalDeclaration ())
  type MDict   = State Dict
  instance Ord Type where
    compare t1 t2 = compare (typeHash t1) (typeHash t2) 

  -- FIXME: this ignores the order, which is not used in the Map.  Is
  -- there an automatic way to do this hashing of arbitrary data
  -- structures?
  typeHash (Type AFloat o) = 2
  typeHash (Type AInt   o) = 3
  typeHash (Type ABool  o) = 5
  typeHash (Type AVoid  o) = 7
  typeHash (Type AFun   o) = 9
  typeHash (Type (AStruct ts) o) = product $ map typeHash ts

[1] http://ogi.altocumulus.org/~hallgren/Programatica/tools/pfe.cgi?Control.Monad.Writer