It's not what programming languages do, it's what they shepherd you to
This is what people mean when they say Haskell is &quot;opinionated.&quot;<p>Haskell shepherds you into separating out IO code from library code to such an extent that literally any function that has an IO action taints the value returned from that function, causing it to be an IO value, and trying to pass that IO value into another function makes the return type of that function IO, too. Parametric polymorphism is the default, too, so it also shepherds you into writing general purpose code. Haskell is full of these little decisions where it just won&#x27;t let you do something because it&#x27;s not &quot;correct&quot; code, and they kind of don&#x27;t care if that makes coding in it a fight against the compiler.<p>Rust took that philosophy and applied it pointers. Every value has a lifetime and an ownership which makes it quite hard to do things that aren&#x27;t memory safe.<p>Both Rust and Haskell wrap values that can fail in little boxes, and to get them out you have to check which type of value it is, and in C# there&#x27;s nothing stopping you from returning null and not telling anyone that you can return null, and just assuming people will check for null all the time. Haskell has a philosophy of &quot;make invalid code unrepresentable.&quot; The concept of a value being in a box, rather than null being a possible value makes it impossible to use that value without getting it out.<p>People who write Go love that concurrency is easy and Go fmt has enforced a single canonical style. Building these sorts of things into the language goes a long way in getting them adopted and becoming the norm.<p>I think we saw a rise of the easy, anything-goes, screw-performance scripting languages. I think the next fashion seems to be in enforcing &quot;correct&quot; coding style. They all have their place.