It ticks, or half ticks, most of the points in the "Benefits of Using Haskell" section. Whilst also coming armed with C# interop and integration with the .NET ecosystem in which they were already invested.
It ticks, or half ticks, most of the points in the "Benefits of Using Haskell" section. Whilst also coming armed with C# interop and integration with the .NET ecosystem in which they were already invested.
I'm not familiar with F# but Scala at least has a far inferior compiler (compared to GHC). There are a lot of functional techniques that simply don't make sense when you don't have dedicated tooling to support them.
The same goes for mutability, it is there and you should certainly use it when it makes sense but it is not the default.
This is also true for Haskell. It's not especially hard to get and use mutable variables, they're just not something that most tutorials cover.
(Yes, Haskell does have unsafePerformIO and the like for special cases, but the expectation is still that the external interface remains pure. If you deliberately circumvent the language's protections and fail to adhere to this rule then you get to keep both pieces when it inevitably breaks. The compiler is still going to operate under the assumptions that the result depends only on the explicit inputs and that evaluating the function has no side effects.)
Lots of people are fond of pointing this out, but very few are actually able to reason about performance of lazy data structures.
Laziness is, in my opinion, the wrong default.
Lots of people say this, very few understand what it actually means and how to do the analyses.
> Laziness is, in my opinion, the wrong default.
Unfortunately, GHC is still the only compiler with first-class support for laziness as well as strictness. And you need both if you want to be able to do immutable functional programming.
But in the grand scheme of things it doesn't really matter if you know what you're doing when you use data structures. Some data structures are meant to be strict, others lazy. Haskell allows you to create data structures that are strict in the right places fairly cheaply.
In strict-by-default languages one must decide up front whether to permit evaluation to be deferred, and there is a cost to be paid via more awkward syntax to first capture the deferred computation and then explicitly evaluate it. This also tends to add runtime overhead which a Haskell compiler would optimize out in cases strict evaluation can be inferred. As a result, libraries generally expose only strict interfaces—and while most lazy functions can easily be made strict in Haskell with judicious application of `seq`, the reverse is not so simple.
Sure, sometimes excessive laziness becomes a problem. However, these cases are not that common, or particularly difficult for an moderately experienced Haskell coder to identify or work around. Enforcing strictness-by-default just because one does not foresee a need for laziness, without any evidence that laziness is negatively impacting performance, would be a form of premature optimization.