It's important to take this kind of advice in it's context, which I would hand-wavingly describe as "imperative old-fashioned OO".
For example, the advice "Pattern 2: Switch to Polymorphism" definitely does not hold in languages with algebraic data types, where the compiler will check that your "switch" expressions check all possible cases. Given that at least Rust, Swift, Scala, and Typescript can all do this, this kind of advice is becoming increasingly outdated.
As a matter of fact it does. Polymorphisms come in many forms (pun intended). The OO-pattern of class inheritance is simply just one of them - not quite so good too if you ask me :)
The author seems to believe that polymorphism is OO-specific. But it isn't. As a matter of fact, if/switch statements are _also_ polymorphic, often used in more procedural code.
The more functional way to match on different type constructors is a fine example of a polymorphic function.
> As a matter of fact, if/switch statements are _also_ polymorphic, often used in more procedural code.
Polymorphism has a straightforward meaning, that the same code is operating on different data types. Switch statements (if's are just a special case) are running different code on different types, so they're monomorphic.
> The more functional way to match on different type constructors is a fine example of a polymorphic function.
I think I see where you're coming from. Here's an example of what you're talking about.
data Foo = Foo Int | Bar String | Qux
what :: Foo -> Foo
what (Foo num) = Bar $ show num
what (Bar str) = Qux
what Qux = Foo 0
That's not polymorphic; there's a single type there, and any given code is strictly acting on a single type of data. It's just a nice way of writing a case.
And, in fact, you find out it's not magic because it gets just as messy and confusing once you have to nest logic as with imperative programming, for example, if Foo contained another ADT, I'd often have to use a case statement or equivalent to manage it.
It's also important to consider comments in context :-) The advice I was commenting on explicitly advised against using switch statements.
I agree with everything else you've said.
(For the pedantic: one can argue about the definition of polymorphism. "Type constructors" do not create distinct types in an algebraic data type as implemented in ML and Haskell, so arguably destructing an algebraic data type using pattern matching is not an instance of polymorphism as the input type is not varying. However that is not germane to this discussion.)
For example, the advice "Pattern 2: Switch to Polymorphism" definitely does not hold in languages with algebraic data types, where the compiler will check that your "switch" expressions check all possible cases. Given that at least Rust, Swift, Scala, and Typescript can all do this, this kind of advice is becoming increasingly outdated.