I'm not sure if this answers your questions, but I think this particular problem has a cleaner solution with GADTs:

    {-# LANGUAGE GADTs #-}
    
    data Cmd s t where
      Push :: a             -> Cmd s         (a,s)
      F1   :: (a -> b)      -> Cmd (a,s)     (b,s)
      F2   :: (a -> b -> c) -> Cmd (a,(b,s)) (c,s)
    
    data Prog s t where
      (:.) :: Cmd s t -> Prog t u -> Prog s u
      End  :: Prog s s
    
    infixr 5 :.
    
    cmd :: Cmd s t -> s -> t
    cmd (Push a) s         = (a, s)
    cmd (F1 f)   (a,s)     = (f a, s)
    cmd (F2 f)   (a,(b,s)) = (f a b, s)
    
    prog :: Prog s t -> s -> t
    prog (c :. p) s = prog p (cmd c s)
    prog End      s = s
    
    run :: Prog () t -> t
    run p = prog p ()

Then from GHCi:
    
    > run (Push 3 :. Push 4 :. F2 (+) :. F1 show :. End)
    ("7",())

Maybe you really want GADTs? :)

-Eric