Hacker News new | ask | show | jobs
by godid 2816 days ago
If introducing a functional language was the aim (EDIT: that's my reading of the motivation here) then, given the political context described, I can't help but feel a better choice would have been F#.

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.

5 comments

In my experience, languages that try to bridge OO and functional ecosystems (F#, Scala, etc) tend to suffer from a lot of split-brain / "worst of both worlds" syndrome. You miss a lot of the advantages of FP unless you go all-in on it like Haskell does.
My experience with F# is that functional programming is the default paradigm while object oriented is used when it is required or easier (or required by a C# library you really want). A striking difference with the little Scala I read in the wild (where object oriented was the clear default).

The same goes for mutability, it is there and you should certainly use it when it makes sense but it is not the default.

> 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.

Haskell has confined mutation with the State and ST types, which guarantees that whatever may be going on inside, the external interface to the function is pure. My main problem with F# (and other multi-paradigm / "functional-first" languages) is that they do not provide any such guarantees; purity becomes merely a matter of convention and convenience, not something ensured by the language. This misses the entire point of functional programming, IMHO, which is referential transparency, and greatly increases the complexity since there are things that matter in F#, like evaluation order, which purity renders completely irrelevant in Haskell.

(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.)

> You miss a lot of the advantages of FP unless you go all-in on it like Haskell does.

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.

My thoughts exactly. I'm curious what compelled the author to choose Haskell over F#.
If I recall, F# doesn't require managed IO which just opens up a can of debugging worms to where you have no guarantees of where side effects and impurity are happening.
I'm not familiar with F# but from what I understand it lacks support for laziness, unlike GHC.
I think this is Haskell's biggest disadvantage in industrial sized applications because it significantly complicates debugging and performance reasoning.

Laziness is, in my opinion, the wrong default.

> complicates debugging and performance reasoning

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.

As a counter to this that may make it easier for a company to adopt and reduce the learning curve. Laziness can make it harder for some to reason about performance as an example.
> Laziness can make it harder for some to reason about performance as an example.

Lots of people are fond of pointing this out, but very few are actually able to reason about performance of lazy data structures.

The language does support laziness, it is just not the deafault.
The default is the whole point. Almost any language can support lazy evaluation, given enough boilerplate, but laziness-by-default is a major contributor toward making Haskell code more composable and reusable compared to idiomatic code in other languages.

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.

Don’t forget the importance of Microsoft’s approval, that carries a lot of weight.
And if you ever want to convince a manager that F# could make a difference in productivity/safety/... : http://fpbridge.co.uk/why-fsharp.html
Which points do you believe that F# doesn't tick, or only half ticks?