Looking at XMonad's contrib packages, you'll find XMonad.Actions.WindowGo, which exports the following function:
runOrRaiseMaster :: String -> Query Bool -> X ()
which takes a string argument of the program to run, e.g. "firefox"; and a boolean query that is used to find out if it is already running, via X11 properties, e.g. (className =? "Firefox") (see top of the XMonad.Actions.WindowGo page for variants).
So, all you need is to bind runOrRaiseMaster "firefox" (className =? "Firefox") to the key you want, as explained in XMonad.Doc.Extending, via
((modMask, xK_f ), runOrRaiseMaster "firefox" (className =? "Firefox"))
as part of the key bindings Data.Map of your configuration (details differ with your way of settings this up, i.e, the whole of your xmonad.hs, see Adding Keybindings).
Note that there is no real sense in maximizing a window in XMonad. When you set things up as explained, you'll have Mod4+f act as follows:
- if there's a window with a classname matching "Firefox", it will be focused and set to master, i.e., depending on your recent layout, will be the big window
- if no window matches, Firefox will be spawned and set to master.
Maximizing can be emulated by choosing the Full layout after calling runOrRaiseMaster, as is described here:
("M-<F1>", sendMessage $ JumpToLayout "Full")
(note that this example also demonstrates XMonad.Util.EZConfig allowing easier keybinding definitions)
Combining these two things is possible, too. Both are of type X (), i.e., they are in the X Monad.
Using >>, which is of type (check with :t (>>) in ghci)
(>>) :: Monad m => m a -> m b -> m b
we have (runOrRaiseMaster "firefox" (className =? "Firefox")) >> (sendMessage $ JumpToLayout "Full") as a combination of two X () types of type X (), too, and it can thus be bound to a key.
EDIT Missing ) in the code line with >>
Edit2 modm -> modMask.
Edit3 This xmonad.hs hopefully works.
(Why not learn you a Haskell for great good?)