> From a Curry-Howard perspective, all JS code is sound: it's unityped, so all programs are proofs of the trivial theorem "true".
Haskell and ML aren't unityped, but, in both, every type is inhabited by expressions. (Caveat: In ML, not all types are inhabited by values, but that doesn't matter, because programs correspond to expressions, not values.) So this doesn't distinguish them from JavaScript.
> From the perspective of equality functions/operators, you're right that it won't be sound; but so what? It's pretty much given that "Javascript foo" is a poor model of "foo", for all values of "foo" (function, integer, boolean, etc.); why should equality make any difference?
Equality matters, because the very first condition to determine whether a procedure computes a function is to see whether it maps equal inputs to equal outputs!
> Just add "==" and "===" to your list of things to avoid, alongside mutation, random numbers, user input and other things which aren't referentially transparent.
That's a different language. Do you know of any good implementations of it? And, FWIW, procedures that compute random numbers are totally fine. You can't rule out procedures that don't compute mathematical functions. You can only keep their use to the minimum necessary.
> To be honest, equality isn't particularly bad if your code has some notion of types/contracts (whether enforced or not); e.g. it's perfectly safe to use "==" when you know that both sides will be strings, for example.
In my day-to-day programming I manipulate more complex data structures than strings.
> Mutation doesn't seem like a great example when discussing (pure) functional programming patterns.
I'm not talking about pure anything. I'm saying that mathematical functions are value mappings, and if the language doesn't let you define compound values (tuples, lists, trees, whatever), then it can only conveniently implement very trivial functions - not enough for practical programming.
> You introduction of the term "usable" seems like a moving goalpost/no true scotsman.
I'm not moving anything. A functional language is one that makes it easy to write functional programs. The lack of compound values means that I'm given two unpleasant choices:
(0) Use Gödel numbers to encode compound values. Would you?
(1) Do imperative programming.