Attached is a patch with a few updates:
1. Added documentation in doc/emacs/mark.texi, under the mark-sexp section. I'm unfamiliar with standards for how the manuals are written, but am happy to update further as needed.
2. Extracted a new helper function mark--helper. This takes two arguments -- a move function, and a number of how many things to move.
The helper function is able to be used for all mark-*-forward and mark-*-backward functions; I think this should handle at least some of your concerns about the composability of the design -- different mark functions can be made by passing a different move function. For example, mark-word-forward and mark-word-backward would be defined this way:
(defun mark-word-forward (&optional number-of-words)
"Mark NUMBER-OF-WORDS words forward.
Repeated calls to this mark more words."
(interactive "p")
(mark--helper #'forward-word (or number-of-words 1)))
(defun mark-word-backward (&optional number-of-words)
"Mark NUMBER-OF-WORDS words backward.
Repeated calls to this mark more words."
(interactive "p")
(mark--helper #'forward-word (- (or number-of-words 1))))
I'm not exactly sure of the best place to put the helper function, nor exactly how the different lisp files in Emacs work together. There's no provide statement; are all the files in lisp/emacs-lisp loaded at the same time? If so, I'll make the other relevant functions (for marking word, defun, page, paragraph, line, and char).
Also, whatever the outcome of this patch, I think it would be advisable to explain somewhere how mark-sexp extends region by the end of region opposite point; this is not in the docstring or any other documentation I've seen.