That first one looks dynamically typed through a List * type, and tags put into pointers. That algebraic type in Haskell also looks dynamic: an Expr can be any one of four things.
This supports the case the article was making. Clearly the type system in Haskell doesn't prevent it from handling arbitrary data - it's hard to imagine a program more open to change in the input data than a Lisp interpreter.
You seem to have a set of rules that you think code in a statically typed language has to follow in addition to the type constraints in order for you to consider it sufficiently 'typed'.
Well, just one rule: if we are looking at type tags at run-time, it's dynamic typing! Whether that be things put into C pointers, or integer fields discriminating unions, or algebraic sum types with pattern matching.
If someone writes Haskell applications by defining an Expr type that is a sum of several dozen things, and then makes al their function arguments and return values of type Expr, is that still bona fide static typing?
Here's one in C (less than 200 lines): https://carld.github.io/2017/06/20/lisp-in-less-than-200-lin...
Here's one in Haskell: https://www.defmacro.org/ramblings/lisp-in-haskell.html