I think a core reason for our success is that we built our team from experienced developers that had built large applications in other languages. Then arrived at Haskell as a better solution.
I have heard some negative experiences that I would attribute to a few different factors.
1. Lack of Haskell experience in the early team. 2. Lack of experience building large real-world applications (too academic) 3. The startup/group didn't achieve product-market fit, and Haskell was scapegoated.
None of these problems are Haskell specific, just run of the mill team issues.
I’ve tried to find a way to use Haskell (lacking strong experience there, but with lots of large app experience), and I’ve not managed to find a situation where pulling the trigger makes sense because of the risk of getting “stuck” with a poor path out.
I'll add this problem is not at all Haskell specific. If you put an experienced Java developer to work architecting a large Python application where they have no prior Python experience you are going to experience similar problems. I'd say the problem is perhaps a bit more acute with Haskell as the paradigm is likely more different to the prior language. So if possible get at least one person on your team that has experience with a large Haskell app and pair them up with other devs.
I would conjecture that it is more common than what you’d expect from random chance. In my case, I picked up Haskell only after building large systems in C++, Objective C, Lisp, and Python. The draw was that Haskell let me express the kind of system invariants that make it possible to reason about a large codebase.
Since then I’ve written production Haskell in three different companies, none of which appear on this list.
Pretty much anything you do in NodeJS/Angular is run-of-the-mill stuff that your run-of-the-mill hires should be able to work on.
It would apply to Haskell though, unless Haskell itself works well as a scripting host.
The difference is Haskell makes these concepts explicit.
Does Haskell have the keyword "monad"?
Does Haskell have support for ensuring that monadic laws hold for any prospective monad?
http://hackage.haskell.org/package/base-4.12.0.0/docs/Prelud...
You have to implement the methods but things like associativity and the existence of identity are not enforced.
Additionally all IO functions in haskell are monads with a return type that is a functor called IO that can contain another type or nothing. You cannot print something to console without invoking a monad in haskell. The clever thing about the IO functor type is that it can only be instantiated by a true IO function that touches some external thing, there is no other way to instantiate this type.
So for example the Instantiated type IO(int) cannot exist unless someone called a function that receives integers from a socket. And to extract the int from the functor you have to use the monadic bind operator.
The only thing special about it is the IO thing I mentioned which is an intrinsic part of the language.
I know you mentioned javascript earlier, just know that while javascript CAN technically have monads, you kind of have to go out of your way to implement it. If you get some experience with a language that has an GADT system and really nail down the concept of a functor you'll see the full power of the monad.
I generally would avoid using a monad with languages that don't have GADT systems.
Haskell is hard to learn and hard to find developers for, but the trade off is incredible safety and a type system that promotes good design and easy refactoring of inevitable design flaws.
To achieve such a thing with other languages you need a highly disciplined team/culture and you need lots of time (meaning less hard deadlines and time crunches) and willingness to invest time into refactoring.
I'm reluctant to believe that Haskell magically protects you from that, but let's suppose it was true. What if my run-of-the-mill gang can rewrite the project three times over before your wizards have congregated to sing their first incantation?
> Haskell is hard to learn and hard to find developers for, but the trade off is incredible safety and a type system that promotes good design and easy refactoring of inevitable design flaws.
Again, I'm reluctant to buy into that. Even if that was true, unless you're writing Haskell in a vacuum, you're going to have to interface with various other horrible pieces of technology that will throw a wrench into your beautiful pure design.
Dealing with the ugly bits while maintaining composure is what makes the difference between a really good engineer and somebody who just wants to program. That quality is invaluable, but you're likely not going to develop it by programming in a language that you enjoy.
i can only show you the door you have to walk through it.
>What if my run-of-the-mill gang can rewrite the project three times over before your wizards have congregated to sing their first incantation?
The 3rd rewrite of your nodejs app still has technical debt. It still has flaws and still is buggy. Every time you redo it, you repeat the same mistakes over and over and over again never knowing how to make things better. You are doomed to participate on an endless cycle of rewrites as people of every generation reinvent the wheel with a new framework and new mistakes never converging on a better solution.
It's a myth that Haskell is slower. The speed I would say is the same because Haskell you would require significantly less testing and validation.
>Even if that was true, unless you're writing Haskell in a vacuum, you're going to have to interface with various other horrible pieces of technology that will throw a wrench into your beautiful pure design.
You do that anyway. At least keep one section of your stack safe and nice. Haskell.
>Dealing with the ugly bits while maintaining composure is what makes the difference between a really good engineer and somebody who just wants to program. That quality is invaluable, but you're likely not going to develop it by programming in a language that you enjoy.
Haskell is about safety and good design. If these two things are not critical to your program, then you shouldn't go the way of Haskell. If it is, Haskell is one of the best technologies to meet that requirement while not costing too much in performance / speed of development.
If Haskell has a critical flaw it's the learning curve. But that's a one time deal. Once you get past the curve you're good. Also don't call us wizards. We're not... Haskell isn't that hard. Anyone can learn it, this isn't like quantum physics. Becoming an expert database SQL ninja admin on postgresql is probably just as hard as becoming one on haskell. haskell like sql is just a bit challenging because it's expression based as opposed to imperative like python.
Oh really? Well that's good news too, because now I can just save myself those rewrites, because they're pointless. That's a 3x improvement right there.
> It's a myth that Haskell is slower. The speed I would say is the same because Haskell you would require significantly less testing and validation.
If you have wizards, that is.
> Haskell is about safety and good design. If these two things are not critical to your program, then you shouldn't go the way of Haskell.
They certainly aren't critical to your run-of-the-mill NodeJS/Angular project which, I must remind, is the alternative that we are discussing here.
> If Haskell has a critical flaw it's the learning curve. But that's a one time deal.
No, it's a "one time per hire" deal.
> Also don't call us wizards. We're not... Haskell isn't that hard.
I'm certainly not calling all Haskell programmers wizards, I'm referring to that "team of experienced developers that had built large applications in other languages (and then arrived at Haskell as a better solution)" that the original commenter saw as a requirement for success.
Of course it's not impossible to assemble such a team for a run-of-the-mill project. It's just impractical.
> Becoming an expert database SQL ninja admin on postgresql is probably just as hard as becoming one on haskell.
See, that's another kind of expert that I definitely don't want to need on the team. I want people who have a basic understanding of SQL, with a reluctance to learn the ins and outs of it. That'll dramatically lower the chances of them trying to be smart with SQL.
No dude don't even write it because likely it will be garbage. If you truly believe that nodejs apps don't need to be rewritten go to Uber. They never rewrote their entire nodejs code base in Golang.
>If you have wizards, that is.
Haskell isn't all wizards. It's just regular people who learned something different.
>No, it's a "one time per hire" deal.
Same with almost every other language that isn't popular yet. Rust and golang and kotlin and swift all went through this. The goal of any language is to become popular enough to get past this.
>I'm certainly not calling all Haskell programmers wizards
Then what is the big deal. If we aren't wizards then it's easy to learn. Programmers learn new languages all the time. Learning Haskell is just slightly more challenging and not a huge drain on productivity. Spend a couple more months training new developers in exchange for a 90% reduction in bugs and much better design.
>See, that's another kind of expert that I definitely don't want to need on the team. I want people who have a basic understanding of SQL, with a reluctance to learn the ins and outs of it. That'll dramatically lower the chances of them trying to be smart with SQL.
Eventually for certain queries you will have to get clever and write queries to optimize. Additionally to serve certain architectures you have to know a lot about the inner workings of the database and how to manipulate the api to get the performance needed at the lower level. An expert has no trouble with this and is an asset. This isn't about getting clever or doing tricky things with syntax just to be clever... this is about inevitability of the fact that a client will want to ask a question to a database that has grown so complex it is not straightforward to answer his question in a performant way. This is extremely common even for your run of the mill web app company.
But that's besides the point. I'm comparing haskell to SQL because it's a similar learning curve. Both are expression based languages. In fact I would argue that Haskell is EASIER then SQL due to the type checking.
Learn the language if you really want to understand our perspective. I use to be in that camp of why learn a freaking language when it's barely used, but that changed once I learned haskell.
There is no "big deal". You're taking my facetious use of the word "wizard" the wrong way.
> Same with almost every other language that isn't popular yet. Rust and golang and kotlin and swift all went through this.
If Haskell already was popular, it would be an entirely different argument. Then we can talk about the merits of the language/platform versus the alternatives. Right now you're trying to sell me this exotic language used by exotic programmers who have strong opinions on design. From a business point of view, those are alarm bells. That's what you need to at least recognize, even though you disagree.
> Learning Haskell is just slightly more challenging and not a huge drain on productivity. Spend a couple more months training new developers in exchange for a 90% reduction in bugs and much better design.
This is what you believe and take for granted in your argument. I'm sure you're sincere about that, but remember, I'm not buying all those beliefs wholesale. Haskell has been around for thirty years, if it really makes for such vast increases in its productivity, why aren't those Haskell programmers dominating software development?
> This just tells me you're someone with little experience.
At least consider the possibility that there's some insight there that you don't quite grasp yet.
> Learn the language if you really want to understand our perspective.
"Buy the product in order to see why it's so great!" would be a terrible sales pitch, if you catch my drift.
And your taking my statement the wrong way. If there really is no big deal then there is really no big deal in me telling you and you actually learning it.
>If Haskell already was popular, it would be an entirely different argument.
If we are here to debate about popularity, then you win buddy. Haskell is not popular. That much is obvious. Every language starts somewhere and I'm here to promote why it should be popular. If you can't buy into that then well there's no point in talking. I get your point. Haskell is exotic and niche. But this is already stupendously obvious so why bring it up. If you don't want to use it for popularity reasons that's a valid point. But that does not discount the technical merits that lend positive credence to why you should use it. 90 percent less bugs then JavaScript is a technical feature that has profound impact on business as does 90 percent less developers.
> if it really makes for such vast increases in its productivity, why aren't those Haskell programmers dominating software development?
JavaScript was a language designed in a week and is largely universally considered to be a terrible language. Why does it dominate the software ecosystem? Because of circumstance and ease of adoption, that's it. Adoption rate isn't an accurate metric on productivity of a language. In fact these studies on productivity have been done before. The language that won was smalltalk.
>At least consider the possibility that there's some insight there that you don't quite grasp yet.
Why don't you tell me what your thinking rather then ask me to consider something that exists only in your mind.
>"Buy the product in order to see why it's so great!" would be a terrible sales pitch, if you catch my drift.
I do catch your drift. And you're right. Unfortunately my arguments don't seem to away you... If arguments don't away you than trying it is logically the only way left. But guess what free trial! Life time access. If you don't like it or if you like it, it's still yours, free!
I'd just like to call attention to this. There is no wizardry to learning (basic) Haskell very well, i.e. to such a degree that using an Elm-like library would not be an obstacle to getting the job done.
You may not ever learn advanced Category Theory, but that -- contrary to popular belief -- is not actually necessary. You may end up using some libraries that use Category Theory at an advanced level (lens), but at absolute worst we're talking learning to parse compiler error messages that are about 1-5% of what a C++ compiler will spit out at you.
Also... when did we want to stop learning?
Are you seriously suggesting that code written in Haskell cannot have bugs, flaws and technical debt?
> Every time you redo it, you repeat the same mistakes over and over and over again never knowing how to make things better.
Am I to understand that people writing in JS cannot learn from mistakes, but people writing in Haskell can?
Haskell is a cool language, but you are not helping its image by such outlandish claims.
No way. Not at all. I am suggesting that Haskell code will have significantly less bugs and less technical debt not none. I am not making a single outlandish claim.
>Am I to understand that people writing in JS cannot learn from mistakes, but people writing in Haskell can?
Yeah. Every couple years people who write JS come up with new garbage frameworks that don't really move the needle forward. React, angular, vue, jquery.... different flavors of the same issue while fixing old problems and creating new ones. Of course their's slight progress forward with things like type script but overall I see the same mistakes being repeated every generation. History repeats itself is a popular saying because there are just as many people who don't learn as there are people who do.
>Haskell is a cool language, but you are not helping its image by such outlandish claims.
Maybe you should understand my claim before calling it outlandish. Significantly less bugs and less technical debt is a real thing, but nowhere did I claim ZERO. You still need unit tests and you still need to think about your design.
Perhaps it's my fault. My comments deliver a perception about haskell that is false. I'll think about it, but in no way did I intend to imply anything outlandish about haskell.
People needed to figure out how to turn HTML into a somewhat usable application platform while it is evolving. The DOM of 2019 is not the DOM of 2009. Javascript ES6+ is far different from ES3. It's chaotic, but how could it not be?
The other day, someone posted a link on writing Haskell for the web frontend. Guess what, people were reinventing things over and over there too, it's just that nobody really took notice of it.
I presume this is in contrast to the Haskell community where there is a single perfect web framework which solves all problems for everyone?
I presume that after I say this to you you’re going to stop communicating with me because shoving random presumptions up someone’s mouth isn’t a polite and civil way to communicate. Prove me wrong.
It just "garbage" and "mistakes" and "people who don't learn" - how do anyone argue against that?
It’s a cheap but affective method to use details to attack generalizations. However the insidious thing about generalizations is that details can be dismissed as noise irrelevant to the main point. A real argument against a generalization is another generalization, with supporting evidence.
Is there any evidence Haskell projects take longer than projects done in "run of the mill" languages?
That said, anyone know of a writeup / "post-mortem" of such a failure?
I’d much rather, in general, get predictable and understandable semantics and have to struggle for performance than get predictable and understandable performance and struggle for semantics. Even more so, I’d rather use software that faced that profile of challenges. You can see when the program is slow at runtime, but you often can’t see when it’s wrong at runtime.
We come across tons of others, I keep meaning to write down a list.
Not too many haskell bootcamps.
There is a need for haskell but it is not the next language to take over it is missing key features.
Which key features is Haskell missing?
The problem is the ecosystem, tooling. Lack of frameworks/crms/cmses make it a poor choice
Bootcamps try to scale the learning process. In a bootcamp someone can go from nothing to productive/professional in a few weeks. This is not possible with haskell.
I ask because I don't think Haskell is particularly lacking in this regard, and it's successfully deployed in real life software, but I might be missing something.
I would argue that programming languages are subjective. There are many different equally viable ways to model the world and programmers should pick the one that aligns with how their brain works.
I'm not convinced it's possible to objectively rank programming languages from best to worse. They are not fundamental properties of the universe simply mental models devised by humans for humans.
I saw something really cool on the weekend. PHP on the client side as a compiled wasm. This allows someone to go severless and run a cms in the client.
That's a new use for an existing language.. is it suitable for everything? Not until it is.
Better for what, for whom? Every programming problem is basically a unique problem of its own -- else the solution would already exist as source-code. There's no need to re-program the wheel.
Therefore the generic question of "what programming language is objectively better" does not make much sense, unless we qualify the question with: better for what, better for whom.
Here's an example about Haskell. Go to https://tryhaskell.org and enter these:
3
div 6 2
3 + 1.0
(div 6 2) + 1.0
The first line returns 3, and so does the second line. The third line returns 4.0. The fourth line fails with this error: No instance for (Show a0)
arising from a use of ‘show_M552168474310802709512215’
The type variable ‘a0’ is ambiguous
Note: there are several potential instances:
instance Show a => Show (Const a b)
-- Defined in ‘Control.Applicative’
instance Show a => Show (ZipList a)
-- Defined in ‘Control.Applicative’
instance Show GeneralCategory -- Defined in ‘Data.Char’
...plus 106 others
In the expression:
show_M552168474310802709512215
(let e_16210 = (div 6 2) + 1.0 in e_16210)
In an equation for ‘e_155216847431080270951221555216847431080270951221516210621016210’:
e_155216847431080270951221555216847431080270951221516210621016210
= show_M552168474310802709512215
(let e_16210 = (div 6 2) + 1.0 in e_16210)
In the expression:
(let
e_155216847431080270951221555216847431080270951221516210621016210
= show_M552168474310802709512215 (let ... in e_16210)
in
e_155The type of `3` gets inferred as `Num a => a` because there's nothing to constrain it further.
The type of `div 6 2` gets inferred as `Integral a => a` because the type of `div` is `Integral a => a -> a -> a`.
The type of `3 + 1.0` gets inferred as `Fractional a => a` because of the decimal point.
Then the same thing happens in the last statement so the type of the subexpression `(div 6 2)` (still) gets inferred to `Integral a => a` and the type of `1.0` (still) gets inferred to `Fractional a => a` because of the decimal point.
So at that point you have an expression that's trying to add something constrained to being a whole number to something constrained to being a fractional number and that is ill typed because there is no type you could choose for the overall expression that would meet both sets of constraints.
Edit: When I first replied there was text at the bottom of the message saying that no one could explain why this happens. My comment was addressing that portion of the original message. The behavior itself is not surprising for the same reasons.
Ambiguous type variable ‘a0’ arising from a use of ‘print’
prevents the constraint ‘(Show a0)’ from being solved.
Probable fix: use a type annotation to specify what ‘a0’ should be.
These potential instances exist:
instance Show Ordering -- Defined in ‘GHC.Show’
instance Show Integer -- Defined in ‘GHC.Show’
instance Show a => Show (Maybe a) -- Defined in ‘GHC.Show’
...plus 22 others
...plus 18 instances involving out-of-scope types
(use -fprint-potential-instances to see them all)
In a stmt of an interactive GHCi command: print itGHC is a little better.
GHCi, version 8.4.4: http://www.haskell.org/ghc/ :? for help
Prelude> (div 6 2) + 1.0
<interactive>:1:1: error:
• Ambiguous type variable ‘a0’ arising from a use of ‘print’
prevents the constraint ‘(Show a0)’ from being solved.
Probable fix: use a type annotation to specify what ‘a0’ should be.
These potential instances exist:
instance Show Ordering -- Defined in ‘GHC.Show’
instance Show Integer -- Defined in ‘GHC.Show’
instance Show a => Show (Maybe a) -- Defined in ‘GHC.Show’
...plus 22 others
...plus 18 instances involving out-of-scope types
(use -fprint-potential-instances to see them all)
• In a stmt of an interactive GHCi command: print it fn main() {
println!("{}", (6 / 2) + 1.0);
}
fails to compile with the following error message: error[E0277]: cannot add a float to an integer
--> src/main.rs:3:28
|
3 | println!("{}", (6 / 2) + 1.0);
| ^ no implementation for `{integer} + {float}`
|
= help: the trait `std::ops::Add<{float}>` is not implemented for `{integer}` fn main() {
println!("{}", 3 + 1.0);
}
Also fails with substantially the same error message. Rust is consistent that you can't add integers to floats. Haskell's looseness around numeric literals means that it isn't.Mind you, Rust does have that kind of looseness within the integers, so this:
fn three() -> u8 { 3 }
fn one() -> u16 { 1 }
fn main() {
println!("{}", 3 + 1);
println!("{}", 3 + one());
println!("{}", three() + 1);
println!("{}", three() + one());
}
Fails to compile only on the last println.For teaching beginners, I very much question the amount of polymorphism in Haskell, and one floated idea has been to use a custom Prelude with much less of it for teaching purposes. Alternatively, I would probably just tell students to read an error like that as "you did something wrong." I would say the same for any student faced with a Java stack-trace showing how their null value threw an exception deep inside library code.
If you're defining instances, you're already an "expert", so why are you defining instances that are "hostile" to your beginner students?
If people in the ecosystem are defining hostile instances, you should probably just ask them to stop it...?
EDIT: Also, isn't failing to compile the almost-optimal case? It certainly doesn't fail at runtime.
There's a similar situation with the now classic:
Prelude> length ['a','b']
2
Prelude> length ('a','b')
1
Here, beginners are potentially being burned by the fact that "length" is polymorphic with the type: length :: Foldable f => f a -> Int
which is not a type I want to explain to beginners. At the same time, as an expert, I want length to be polymorphic and don't want to sacrifice its polymorphism for the sake of beginners.I think the problem there is really calling it 'length'.
Prelude> :t (div 6 2)
(div 6 2) :: Integral a => a
Prelude> :t 1.0
1.0 :: Fractional t => t
Bonus: there is a language extension which does you do this: https://www.schoolofhaskell.com/school/to-infinity-and-beyon...
If your point was that the error messages could be nicer, I agree.
Solution:
(fromInteger (div 6 2)) + 1.0
I wouldn't advice against Haskell. But I would advice against having a business with more than one non-boring component. And usually that non-boring component should be the solution to the client problem, not the tech stack used to implement it.
If you start a business in a language stack none of the devs have done large scale production projects, you are basically begging for a world of trouble. If the devs are familiar with Haskell, I don't see any problem with choosing it, if it matches the problem domain. I wouldn't choose it for example for frontend development (although I suppose you can get it compiling there) or things where C, C++ or Fortran still have a strong legitimate foothold.
(I have no idea what would motivate a person to do such a thing, but people are weird.)
"What can be asserted without evidence can also be dismissed without evidence." (Christopher Hitchens)