The idiom of using undefined to replace BangPatterns has a few benefits, which is why it gets used in libraries like bytestring. It doesn't require a language extension and applies a bit nicer in macro expansion because it infects one line of your patterns rather than either mangling all pattern matches or relying on subtleties about whether or not the pattern match earlier was enough to 'forget' the strictness of a later pattern when it isn't strict in a subsequent pattern.
foo !(Bar x) !(Bar y) = ...
foo y w = ... am I strict in w?
foo x y | seq x (seq y False) = undefined
foo (Bar x) (Bar y) = ...
foo y w = ... is definitely strict in w
Other usecases are for working with combinators like sizeOf, alignment, bitSize, bitSizeMaybe, finiteBitSize, or doing things like initializing self-referential IORef structures whenever you do have to tie the knot strictly, etc. In the former cases you can argue that the API should change to take a Proxy, then spend a couple of years driving that change process through, as most of them affect the current language report, but in the latter case you're basically stuck with either embracing momentary partiality and knowledge of lack of escape or working with inaccurately weak types after the structure is initialized, forever.
-Edward