In my music translation program, I have a ton of data and configuration that goes into every note computation, so I've decided to use the State monad to pass it around. Also, the generated output is just a list of MIDI events, so I think I'll use Writer to gather the output. 

I will be dealing with several different MIDI synthesizers, which have different specifications and manner of control. But there is enough in common that I can write a single function to do the translation, provided that I provide that function with some data that is specific to the synth, and also I need to configure it with some functions specific to the synth. 

Let's say my State/Writer type is called Tr.

type Tr a = StateT Configuration (Writer [MidiEvent]) a

This is the data I provide to StateT:

data Configuration = Configuration
  { t1 :: SynthSpecificData
  , f1 :: Tr SynthSpecificComputationResult
  , score :: WholeMusicalScore
  }

So I need to write 

translate :: Tr ()

computeMidiEvents = runWriter (runStateT translate theConfig)

So inside 'translate' I want to call 'f1' among many other things. Let's just consider the f1 call first. I wrote this first:

translate = do
  f <- gets f1
  f

That works but looks a little weird. I think this works also:

translate = join (gets f1)

Is that better?

D