[HN Gopher]  Haskell is our first choice for building production...
       ___________________________________________________________________
        
        Haskell is our first choice for building production software
       systems
        
       Author : Albert_Camus
       Score  : 251 points
       Date   : 2021-01-11 09:24 UTC (12 hours ago)
        
 (HTM) web link (www.foxhound.systems)
 (TXT) w3m dump (www.foxhound.systems)
        
       | gregorygoc wrote:
       | I think most programmers nowadays face no interesting problems to
       | solve. They crave for a mental challenge, but instead of looking
       | for a job that requires solving hard engineering problems, they
       | believe they can satisfy their mental needs with coding in
       | "somewhat" hard language.
        
         | dbattaglia wrote:
         | I think you make a valid point in general about coding
         | professionally at most jobs, and I know I've fallen into this
         | desire myself while working on endless CRUD apps over the
         | years. That said, I do think the article brings up some good
         | points about domain modeling. After becoming somewhat
         | proficient in Scala I've found these same features (ADTs)
         | mentioned in the article helpful for the important part of
         | these boring CRUD apps: modeling data at the various
         | application boundaries (API, domain layer, database layer,
         | etc). I now find using weaker type systems and/or imperative
         | code to be either more error prone or more verbose (due to
         | validation + extra tests).
         | 
         | Of course there are other parts of Scala, Haskell and similar
         | that require more mental gymnastics than I'd like, such as
         | composing asynchronous operations; flatMap and monad
         | transformers may be "elegant" once you really understand them
         | but damn is async/await easier to just write and move on with
         | your life.
        
         | [deleted]
        
         | Tade0 wrote:
         | As a front-end developer whose job is is to write
         | _configurations_ (so not even actual code) for a form library I
         | picked up Rust for this specific reason. Could've been any
         | other language, but this one scratches my personal itch.
        
       | unicornmama wrote:
       | Good luck scaling this to organization of 100+ engineers. You
       | will soon learn the tradeoff between writing and reading code.
       | And the stark realities of the dev hiring markets and the thing
       | called a learning curve.
        
         | mightybyte wrote:
         | You're off by probably an order of magnitude. You can
         | absolutely scale this organization to 100+ engineers. I've
         | worked at a company with ~30 Haskell developers and I was
         | involved in hiring most of them without lowering our hiring
         | bar. If we really needed more it would have been quite easy to
         | lower the bar a little and increase the numbers significantly.
         | Here's another example of a company that has a large Haskell
         | team:
         | 
         | https://iohk.io/en/team/#team=development
         | 
         | Now if you needed to hire 1000 developers, then you'd have more
         | of a problem, and perhaps Haskell wouldn't be the right
         | approach. But in my experience, Haskell engineers get a
         | multiplier effect over the average non-Haskell engineer because
         | the code is more concise and the average engineer skill is
         | higher. I don't know what the multiplier is, but it's
         | definitely non-zero and positive. This not only pays the
         | obvious direct benefits, but also reduces the communication
         | overhead of your team and the number of managers you need to
         | hire.
        
         | fegu wrote:
         | Using "boring" Haskell (less higher level magic) alleviates
         | this to some extent - without being boring. The organzation
         | should decide which features and code styles to use. I agree
         | that the summer intern's multi-layer home-built monad
         | transformer stack and custom operators can be a pain.
        
         | __0x01 wrote:
         | I've found that code readability decreases (for me) with the
         | generous use of <$> and $.
         | 
         | Edit: removed ` characters.
        
         | cies wrote:
         | Not sure, but how big are the pools of Haskell-devs over at
         | Galois, FPComplete, HKIO, Facebook, Tsuru Capital, Type Safe,
         | ...?
         | 
         | Probably under 100, but not sure though.
         | 
         | I dont think this learning curve/hiring thing makes sense.
         | Haskell can help attract smart dev, it makes refactoring so
         | easy increased learning curve is off set.
         | 
         | I'd say it's harder to outsource, and there may not be as many
         | libraries. Compare to Ruby/Rails for web, or Python for ML, and
         | you have to write more by yourself in Haskell.
        
         | erik_seaberg wrote:
         | Is is actually hard to hire for Haskell? You can't just tell
         | some random to learn it (because his head will explode), but my
         | impression is that you'll have candidates coming out of the
         | woodwork who could never get away with using it before but
         | _always wanted to_.
        
           | egwor wrote:
           | Quite a few universities in the UK teach haskell as a way to
           | start everyone on a level playing field and to introduce
           | various concepts.
        
             | rednum wrote:
             | Similar situation in Poland. Also my anecdotal experience
             | is that Haskell classes are not considered to be the most
             | difficult, rather they are somewhere in the middle.
        
               | dagw wrote:
               | The University I went to in Sweden used Haskell for its
               | intro classes. Intermediate classes where taught in Java.
        
           | pwm wrote:
           | Single datapoint: The last time I posted a job ad (I was the
           | hiring manager) I got ~40 good applicants within a week. I
           | expected much less and got pretty overwhelmed.
        
           | dllthomas wrote:
           | In my experience, it's easy to hire the next Haskell
           | programmer and hard to hire the next ten.
           | 
           | My experience with onboarding non-Haskellers has been pretty
           | good, though I would certainly admit the argument that they
           | were unusually talented individuals.
        
         | nix23 wrote:
         | Ever heard of Pandoc? With your logic, python is the only
         | reasonable language.
        
           | detaro wrote:
           | I don't think "have you heard of this project with <5 main
           | contributors" is a useful response to questioning if it
           | scales to large groups.
        
         | bachmeier wrote:
         | Thanks for sharing, but honestly, what does your comment add to
         | a discussion of the post, which is about what works for them?
         | You're making a rude comment that assumes they don't already
         | know these things. Have you considered the possibility that the
         | tiny slice of the world you've experienced is just that?
        
           | secondcoming wrote:
           | Because what works for one company may not work for another.
           | It's useful to point to any potential cons of a particular
           | approach.
           | 
           | I didn't find the comment rude.
        
             | bvaldivielso wrote:
             | Their point is valid, though the comment reads
             | condescending to me. Maybe it reads condescending to me
             | because I don't agree with it, but I believe it could have
             | been phrased in a less adversarial way:
             | 
             | <<Haskell does not scale to organizations of 100+
             | engineers. There is a trade-off between writing and reading
             | code, which Haskell does not fare well in. Also, given the
             | realities of the dev hiring market, steep learning curves
             | would be very detrimental to the success of the company>>
             | 
             | What would have been your reaction if I had replied "look
             | up the word condescension in the dictionary" to you? It
             | would lead to bad discussion, regardless of whether my
             | point about condescension was right or not.
        
         | infinityplus1 wrote:
         | Someone has to take the first step to solve the chicken and egg
         | problem. If there are jobs requiring Haskell, it might get more
         | users.
        
           | 414owen wrote:
           | I write Haskell professionally, and I can confidently say
           | that there are plenty of jobs. Some large tech companies (eg.
           | Facebook, GitHub, Twitter), quite a few banks, a lot of
           | consultancy companies, and plenty of random companies I'd
           | never heard of.
           | 
           | It is quite difficult to get a first Haskell job though,
           | because they mostly require production Haskell experience, so
           | there's your chicken and egg problem.
        
             | PietPtr wrote:
             | Working with Haskell professionally sounds like a very
             | interesting career path. Could you point to some resources
             | to get better at the production Haskell skills that these
             | companies are looking for? Perhaps gaining experience with
             | projects which use Haskell in a similar way to the
             | companies you mention could help with finding that first
             | Haskell job.
        
               | 414owen wrote:
               | Sure thing.
               | 
               | I'm not sure what your current level is, but I can give
               | some general advice for people that happen upon this:
               | 
               | ---
               | 
               | Haskellers are generally expected to understand most of
               | the typeclassopedia
               | (https://wiki.haskell.org/Typeclassopedia), don't worry
               | about learning it all in one go. I had to read this page
               | many times before I grokked most of it.
               | 
               | ---
               | 
               | Avoid tutorials that overuse analogies. A Monad only adds
               | one operation to Applicative:                 class Monad
               | m where         (>>=)  :: m a -> (a -> m b) -> m b
               | 
               | This reads as: `m` is a monad if, given an `m a`, and an
               | `a -> m b`, you can construct an `m b`.
               | 
               | ---
               | 
               | It's important to be really good at using Monads that
               | support multiple effects, to create little DSLs. If I
               | want a component of my program to support throwing
               | errors, creating a log, and reading an environment, (all
               | purely), I'd use something like this:
               | type MyDSL         = ReaderT Environment
               | (WriterT [String]               (Except ErrorType))
               | 
               | These are monad transformers from the mtl library.
               | 
               | Where I work we use free monads instead of monad
               | transformers, but that's just an implementation detail,
               | it's used the same as a transformer stack.
               | 
               | ---
               | 
               | Create a cool project, Haskell people like languages.
               | When I was interviewing I showed off a tiny lisp-like
               | language implemented in Haskell
               | (https://github.com/414owen/phage). This was my first
               | non-trivial Haskell project so don't judge it too
               | harshly.
               | 
               | ---
               | 
               | Read Haskell Weekly
               | (https://haskellweekly.news/newsletter.html). It's a
               | great source of ideas and knowledge.
               | 
               | ---
               | 
               | A lot of Haskell shops use, or are migrating towards
               | using, nix (https://nixos.org/).
               | 
               | ---
               | 
               | Apply! The Haskell market seems to favor the interviewee.
               | In the end, I had more than one offer, even for my first
               | Haskell job.
               | 
               | Good luck!
        
               | PietPtr wrote:
               | That's very insightful, thank you!
        
           | st1x7 wrote:
           | I don't think that it's wise to sabotage your own future and
           | productivity as a company just so you can pave the way for
           | some language to become more popular.
        
             | mjburgess wrote:
             | It isn't, of course. But the crowd of other people want you
             | to do that.
             | 
             | It's the role of applause (and in your case, downvotes).
             | The crowd throws cheap adulation at individuals who act
             | against their own interests.
        
               | oblio wrote:
               | The peanut gallery :-))
        
             | mightybyte wrote:
             | I don't think that it's wise to try to optimize for some
             | kind of speculative long-term success at the expense of
             | higher early-stage costs that reduce your odds of getting
             | there. This is similar to companies that choose their
             | initial technology with scalability in mind before they're
             | even remotely close to needing to scale. I've actually done
             | this only to discover that scalability has a very definite
             | cost and when you're small it has an outsized impact on
             | your burn rate. If you have success, you're going to figure
             | out a way to make the changes you need. Case in point:
             | Facebook. They successfully grew a PHP codebase into one of
             | the most popular apps in the world. It definitely cost a
             | lot more money for them to make PHP work, but when they got
             | to that point they were a lot less cost-sensitive.
             | 
             | Planning for that far down the road is the least of your
             | worries. And any plans you make along those lines are not
             | likely to be very accurate anyway. You're much better off
             | optimizing for the near to mid term. Based on the hosting
             | costs described by the OP they are already reaping a
             | tangible value here.
        
             | whateveracct wrote:
             | I think at worst, Haskell is a a minor productivity cost
             | for a company vs a mainstream language, and if it is, it's
             | hard to pin it on the language.
             | 
             | So given the upside to paying people to using Haskell (they
             | get to learn it for life, many join + grow the community,
             | they enjoy working for your company more), I think it's
             | worth that kind of harm to a corporation.
             | 
             | I'll keep trying to sap corporate resources into Haskell I
             | take with me for life at least :)
        
         | st1x7 wrote:
         | I feel like this isn't discussed enough. I can't comment on the
         | technical merits of Haskell but growing an organization and
         | replacing engineers is so much more difficult when you're using
         | tools that aren't mainstream.
        
           | vp8989 wrote:
           | Optimizing for worker fungibility, in a vacuum, seems like a
           | -EV "playing not to lose" strategy. It's understandable that
           | this line of thinking is common though.
           | 
           | I also believe that to be the case as an employee. Ie, being
           | a generalist is probably -EV for your career but it feels
           | safer so it's kind of a contrarian position to say "be a
           | specialist".
        
             | st1x7 wrote:
             | > Optimizing for worker fungibility, in a vacuum, seems
             | like a -EV "playing not to lose" strategy.
             | 
             | That's why you don't optimise for it in a vacuum. You weigh
             | the potential benefits of switching to Haskell versus the
             | additional cost of maintaining/growing a Haskell team.
        
           | detaro wrote:
           | The market works somewhat differently for small companies
           | there. Yes, there are fewer people with relatively niche
           | skills, on the other hand you have an easier time to attract
           | the few you need. Not every company wants to become large.
        
             | st1x7 wrote:
             | > on the other hand you have an easier time to attract the
             | few you need
             | 
             | How is it easier to find a Haskell developer vs finding a
             | Java/Python/PHP developer?
        
               | detaro wrote:
               | I hear far more complaints about how difficult it is to
               | find good people from companies hiring for mainstream
               | languages than from those using more niche stuff, I would
               | assume mostly due to larger competition among employers
               | for the former (and in parts better community access for
               | small shops in niche languages and self-selection of who
               | learns the niche languages)
        
               | st1x7 wrote:
               | > I hear far more complaints about how difficult it is to
               | find good people from companies hiring for mainstream
               | languages than from those using more niche stuff
               | 
               | Of course, there is just more of them in the first place.
               | The other effects that you describe might also be true
               | but keep in mind what the base rates are.
        
               | dragonwriter wrote:
               | > I hear far more complaints about how difficult it is to
               | find good people from companies hiring for mainstream
               | languages than from those using more niche stuff
               | 
               | I would assume that:
               | 
               | (1) Those using niche stuff are less likely to be hiring
               | under the impression that the main measure of skill is
               | years of experience with a language, and
               | 
               | (2) those using niche stuff are, on average, doing more
               | interesting work that attracts more intellectually
               | curious candidates.
               | 
               | As a result, the mainstream firms get worse candidates,
               | and try to compensate by asking for _even more years of
               | experience_ , and asking for years of experience not just
               | with language but specific libraries and other tools,
               | hoping that will get them more skilled candidates, at
               | least for their specific toolchains. But doubling down on
               | that just gets them candidates that are less capable
               | (because even to the extent years of experience are
               | useful, there are diminishing returns, and people who
               | have spent a huge amount of time with the same stack also
               | are likely to be in the "1 year of experience, repeated N
               | times" category, rather than N years of learning and
               | compounding knowledge. (Also, because at a certain point
               | you start making impossible demands, increasing the
               | degree to which the hiring process filters for
               | dishonesty.)
        
               | tome wrote:
               | I believe it's another example of Paul Graham's Python
               | Paradox, just repeated more than 15 years later
               | 
               | http://www.paulgraham.com/pypar.html
        
               | tome wrote:
               | I've never hired a Haskell developer, but anecdotally
               | from my friends and associates who have, if you put out
               | an advertisement for a Java/Python/PHP developer you get
               | 500 applications from average candidates. If you put out
               | an advertisement for a Haskell developer you get 5
               | applications from good candidates.
        
               | marcosdumay wrote:
               | For reference, that got called the "Python paradox" back
               | then when Google was exploiting it. Of course, Python is
               | now mainstream, so it doesn't have this effect anymore.
        
               | saberdancer wrote:
               | You probably got 500 applications for Java/Python/PHP, of
               | those 450 average and let's say 50 good.
               | 
               | With Haskell you just get 5 good ones. You probably don't
               | start with Haskell as your first language but rather move
               | into it after you are a senior in another language. If
               | you are lousy in Java, you probably won't go and learn
               | Haskell or some other niche language.
        
               | tome wrote:
               | That sounds like a reasonable assessment.
        
         | cosmodisk wrote:
         | They won't scale to 100+. From what it looks, it's a boutique
         | dev shop that likes doing Haskell and they are going to stay
         | that way +/- a few people here and there depending on how
         | successful their projects are.
         | 
         | This may or may not be the right business strategy, however if
         | everyone would be going with a notion of only using popular
         | languages because it's easier to hire for them, by now we'd be
         | using JS as a backend language.Oh,wait...
        
       | IfOnlyYouKnew wrote:
       | No, sorry, it has very little to do with technology. There's at
       | least a dozen languages you could have chosen, and that others
       | have chosen for any given use case. within some bounds, it makes
       | very little difference.[0]
       | 
       | The reason you've chosen Haskell and, by the way, also the TLD
       | ".system", is that you've constructed your identity in such a way
       | that "advanced language with a steep learning curve" is something
       | that fits.
       | 
       | There's absolutely nothing wrong with that. It's a bit emotional,
       | but those exist for a reason. If you consider that idea
       | libellous, you can always cite PR motives for plausible
       | deniability and point at this HN story as evidence.
       | 
       | [0]: Elm, by the way, strikes me as borderline with regards to
       | the bounds of reasonableness, considering the state that
       | community is in. As such, it's more evidence your left (right?)
       | metaphorical hemisphere may have had a finger on the scale.
        
         | willtim wrote:
         | > There's at least a dozen languages you could have chosen, and
         | that others have chosen for any given use case. within some
         | bounds, it makes very little difference.
         | 
         | It's about quality of life and picking the right tool for the
         | job. There are some problems I can solve in Haskell, that I
         | simply could not solve in Java, it would be too hard and too
         | much work. Java is a simple language and therefore it's much
         | easier to reason about the performance and space usage. There
         | are thus many problems where Java would be a better fit.
        
           | sesm wrote:
           | Java is much easier to reason about the performance and space
           | usage because it's a language with strict evaluation. Most
           | programming languages use strict evaluation, including OCaml,
           | F# and Scala.
        
             | willtim wrote:
             | > because it's a language with strict evaluation
             | 
             | But that is not the only reason. Haskell does much more
             | aggressive optimisations than Java (and Scala, OCaml, F#).
             | A large part of Haskell's space-usage reasoning issues come
             | from the combination of lazy evaluation and these
             | aggressive optimisations. Java and Scala code can contain
             | plenty of deferred evaluation too, for example iterators,
             | but the compilers simply don't do (and cannot do) such
             | aggressive optimisations. Of course, this also means that
             | much pure functional Scala/Java code can be poorly
             | performing.
        
         | thedmstdmstdmst wrote:
         | I have no horse in this race. Reading the posted article I have
         | a hard time understanding why you posted this comment. The
         | article has reasoned arguments related to software development.
         | Your comment is pure emotion which seems to be your main claim
         | against the article.
        
           | slow_donkey wrote:
           | I had the same feelings as the parent - this article did not
           | make good arguments for using Haskell specifically in
           | building production systems, it instead argues that Haskell
           | is a good programming language yet many of the benefits
           | listed can be found in other languages.
           | 
           | Even if Haskell was objectively the 'best' language, it'd
           | likely be a poor choice for most teams simply due to
           | familiarity and developer speed.
           | 
           | I'd be extremely hesitant to hire the services of this
           | company entirely because they use Haskell and it'd be a
           | nightmare to maintain after their contract.
        
             | thedmstdmstdmst wrote:
             | I think the article was easy enough to pass by as I agree
             | it didn't make GOOD arguments specifically in building
             | production systems. I also give the author some slack
             | because that article would be quite heavy to address the
             | entire development cycle up to production systems.
             | 
             | From my reading the article makes no claim that Haskell is
             | the best language. The purpose as I read it is to explain
             | why Haskell is their first choice while addressing an
             | audience that has a passing knowledge of Haskell.
             | 
             | You being extremely hesitant to hire the services because
             | of their technology stack is great and fine. There are many
             | stacks and services I completely avoid in dealing with so I
             | agree there.
             | 
             | "It'd be a nightmare to maintain after their contract" is
             | something someone would likely say to any language that is
             | not their preference.
        
         | boomlinde wrote:
         | Why don't you argue against the points made in favor of Haskell
         | in the article? You can probably tell more about why they use
         | Haskell that way. It's certainly a better indication than your
         | ridiculous TLD divination.
        
         | FlyingSnake wrote:
         | > The reason you've chosen Haskell and, by the way, also the
         | TLD ".system", is that you've constructed your identity in such
         | a way that "advanced language with a steep learning curve" is
         | something that fits.
         | 
         | I think you're projecting too much on them. They found Haskell
         | performant and are promoting it, I don't see any problem with
         | it. How is any different from all the Rust evangelism HN sees
         | all the time?
        
           | IfOnlyYouKnew wrote:
           | I really don't have a problem with their choice-I wasn't
           | being ironic. It's perfectly acceptable to make "I like it"
           | or "it works for us" choices.
           | 
           | I do believe, very very mildly, that there's a strain of
           | thinking among the tech crowd that glorifies this Spock-like
           | emotional detachment and I'm-so-rational mindset. Two issues,
           | actually:
           | 
           | First, such a mindset is neither possible nor would do much
           | good. There are stroke victims that survive with full mental
           | capabilities with regards to logical reasoning but entirely
           | devoid of emotions. These patients can still ace the SAT, but
           | they fail spectacularly at daily life. As it turns out, you
           | just cannot decide on a doctor's appointment without
           | emotions. They'll spent hours vacillating between two good
           | choices. Emotions are incredibly well-tuned heuristics that
           | cut down your mental load to manageable levels. As any part
           | of being human, they are sometimes ill-fitting for modern
           | times: there's absolutely no reason to make me flinch when I
           | spill hot coffee over my hand. But mostly they just work.
           | 
           | Second, it's slightly annoying when people deny that they are
           | subject to emotions, and it gets up to Ryanair-levels of
           | discomfort when they announce that it makes them superior to
           | all those emotional social science majors, illogical
           | politicians, women "throwing a fit", superficial designers
           | etc. If I got a KDE theme every time someone accused Apple
           | users of being blinded by eye candy, I'd still be left with
           | only half of what Kubuntu ships.
           | 
           | But Rust is cool.
        
             | thedmstdmstdmst wrote:
             | I completely agree about your thought about emotions and
             | the Spock-like emotional detachment and the importance of
             | emotions in decision making and every day life.
             | 
             | I disagree that this is related to the original posted
             | article about a company that has chosen as their first
             | language Haskell. I do wonder how your responses would
             | differ if they had chosen Elm originally and perhaps it is
             | both you and I that should evaluate our emotions are why we
             | even commented...
        
             | arcturus17 wrote:
             | I think these are very keen observations of reality, and
             | they're very well put.
             | 
             | I've long-admitted that my heuristics for choosing a tech
             | stack are very similar to what you describe. I analyze the
             | requirements and give each technology a pass/fail grade.
             | Then, amongst those that pass, I simply choose the one that
             | I find the coolest.
        
             | nobodyandproud wrote:
             | It's believed (by some) that emotion is a necessary
             | prerequisite for intelligence.
             | 
             | Something needs to be a driver for action, and emotions fit
             | the bill nicely.
        
           | oblio wrote:
           | I think his point is that there are N languages that are
           | performant and they could have probably chosen any of them to
           | achieve their goal, so the choice is primarily aesthetic.
        
             | thedmstdmstdmst wrote:
             | The article doesn't say they have exhausted all languages,
             | just that it is their first choice. Not their only choice
             | but first choice.
        
       | elephantum wrote:
       | It seems like you can substitute Haskell to Rust in almost every
       | point they make.
       | 
       | (Or with many other great options)
        
         | adamch wrote:
         | Yes, this was my immediate thought too. I love writing Haskell,
         | but Rust has become my daily driver, both at work (Cloudflare)
         | and personal projects. It gives me the excellent type system,
         | better domain modelling, great ecosystem (serde, actix-web,
         | rayon, reqwest, diesel, tokio) and performance.
         | 
         | I've basically traded away some nice abstractions (functors,
         | monoids etc) for the ability to debug error messages more
         | easily, and not have to convince people to learn/support an
         | obscure language. Good deal IMO.
        
       | Geminidog wrote:
       | Haskell does not actually get rid of side effects in practice. I
       | find that tons of Haskell code involves do notation which is
       | basically code that embraces monadic side effects which sort of
       | defeats the purpose that this article says of pushing side
       | effects to the edge.
       | 
       | Really in order to "push side effect to the edge" people need to
       | avoid using monadic composition as much as possible which I see
       | Haskell programmers rarely doing in practice.
        
         | willtim wrote:
         | Monadic composition is used everywhere from simple failure
         | (Maybe or Either) through to genuine side effects such as IO.
         | The presence of monads does not necessarily mean side effects.
         | 
         | Haskell never claimed to "get rid of side effects", the idea is
         | make them explicit in the types and to be able to reason about
         | them.
        
           | Geminidog wrote:
           | Right, but the article says that Haskell pushes these side
           | effects to the edge. I am not saying haskell claims this, I'm
           | saying the article claims this. Haskell actually doesn't do
           | this in practice as tons of people use do notation and state
           | monads. The more people use do notation, the more they are
           | embracing side effects. Literally I've seen haskell code
           | where all function definitions had some form of do notation
           | which is basically against the claim made by this article.
           | 
           | To push side effects to the edge you have to only use do
           | notation and monads when you absolutely have no choice, which
           | is not done in practice with haskell.
           | 
           | >The presence of monads does not necessarily mean side
           | effects
           | 
           | The presence of a functor does not mean side effects. The
           | presence of a monad implies composition and binding which
           | does imply a side effect. Even maybe monads composed have
           | side effects that can produce output that the function itself
           | can never produce on it's own.
           | 
           | For example let's say I have a maybe monad that will never
           | produce "Nothing."                  b :: int -> Maybe Int
           | b x = Just x
           | 
           | but I can produce a side effect by binding it with Nothing.
           | Nothing >>= b
           | 
           | The above yields "Nothing," even though it is not part of the
           | definition of b. It is a contextual side effect passed on
           | through monadic composition. Normal composition outside of
           | monadic composition usually does not have this property.
        
             | willtim wrote:
             | You seem to be lumping all side-effects together as equally
             | bad? I don't think you can expect to push everything out to
             | the edges, for example partiality. I take your point that a
             | lot of imperative programming is done in Haskell (e.g.
             | State monads). However, I think what most Haskellers mean
             | when they talk about pushing effects to the edge, is
             | pushing IO and other less benign effects.
        
               | Geminidog wrote:
               | >You seem to be lumping all side-effects together as
               | equally bad?
               | 
               | Never implied anything was bad or good. Just saying that
               | Haskell style programming does not push side effects to
               | the edge.
               | 
               | >I don't think you can expect to push everything out to
               | the edges, for example partiality.
               | 
               | Of course you can't push everything to the edge, but
               | haskell style programming doesn't attempt to do this. It
               | embraces the side effects and no one actually pushes
               | anything to the edge. Partiality was just an example, the
               | point is the bind operator will have a side effect on b
               | so you can no longer treat the output of b as a pure
               | black box. People who use haskell use the bind operator
               | all the time indicating that their code is littered with
               | side effects. Which again isn't necessarily bad, it just
               | is what it is.
               | 
               | >However, I think what most Haskellers mean when they
               | talk about pushing effects to the edge, is pushing IO and
               | other less benign effects.
               | 
               | But my argument is this is not often done. I've seen tons
               | of giant IO functions wrapped in do notation. Generally,
               | no big attempt is made to segregate IO or side effects
               | away from pure logic. Everyone just writes a monad and
               | starts using do notation.
               | 
               | Again if you avoid using monads as much as possible in
               | haskell you are pushing side effects to the edge. If you
               | don't do this, which is basically what most haskell
               | programmers end up doing, then you are not pushing side
               | effects to the edge.
        
               | tome wrote:
               | > But my argument is this is not often done. I've seen
               | tons of giant IO functions wrapped in do notation.
               | Generally, no big attempt is made to segregate IO or side
               | effects away from pure logic. Everyone just writes a
               | monad and starts using do notation.
               | 
               | Yeah, "functional core/imperative shell" or "pushing IO
               | to the edges" is a weird myth. Really the strength of
               | Haskell is "functional core/IO code carefully threaded
               | through functional core".
               | 
               | What's a good descriptive slogan for that? "Functional
               | pipework/imperative reactants", invoking chemical
               | engineering?
               | 
               | To cycle back to your point, I don't think the failure of
               | this slogan actually points to any weakness in Haskell.
        
               | Geminidog wrote:
               | >To cycle back to your point, I don't think the failure
               | of this slogan actually points to any weakness in
               | Haskell.
               | 
               | Yeah agreed, it's just a style of programming within the
               | functional paradigm. Not necessarily bad or good.
        
           | eklavya wrote:
           | Well, I don't know why but this submission has attracted
           | particularly misinformed, blatant wrong or hyper emotive
           | responses. Maybe Haskell killed people's pets or something.
        
       | StreamBright wrote:
       | Most of these apply to F#. The only difference that there are
       | much more libraries available for that ecosystem than to
       | Haskell's.
        
       | fegu wrote:
       | If you want to get a feel of the productivity using Haskell in
       | production start with a simple CRUD app and use IHP
       | (https://ihp.digitallyinduced.com/) to build it. You will have
       | something usable within a day - GUI and all. Then move further
       | down the rabbit hole from there.
        
         | WraithM wrote:
         | I find it extremely frustrating that I have to use Nix to use
         | this framework. We don't use Nix at my company, and we likely
         | never will. I can easily incorporate packages from hackage into
         | our codebase. I really don't want to have to vendor this
         | project myself. Why make a great web framework and then create
         | such a large constraint on who can use it reasonably?
        
           | Geminidog wrote:
           | We use nix in production at my company. It's horrible. It's
           | only good for ecosystems that rely heavily on context or
           | libraries installed by operating system package managers.
           | Languages that have self contained package managers like
           | JavaScript, Haskell or python don't benefit. In fact in those
           | cases nix actually makes things worse by making almost
           | everything way more complex and error prone then necessary as
           | literally nothing is designed with nix in mind.
        
         | kreetx wrote:
         | How about servant, and some popular js framework on top of
         | that? IHP might be putting a lot of effort into the project,
         | but the code generation part... I (personally) don't like that
         | at all. And it's not common practice in haskell.
        
           | hardwaresofton wrote:
           | Second this -- Servant is one of the best examples of server-
           | side haskell there is, and from what I understand IHP is
           | relatively new in comparison (correct me if I'm wrong).
           | 
           | Servant is one of the best if not the best example of how
           | haskell's higher level abstractions can benefit practical
           | bread and butter programming (which making APIs is these
           | days) tasks, and where type safety is a huge benefit.
           | 
           | Writing servant handlers can also feel mostly imperative
           | depending on how much you use `do`.
        
           | _query wrote:
           | IHP is very opinionated in the way how it approaches building
           | web applications (Code Gen, Project structure, Naming, ..).
           | But exactly this kind of opinionated design makes it possible
           | to be very productive, compared to doing everything
           | yourselves.
        
             | kreetx wrote:
             | IHP is opinionated in the sense that it does state on the
             | server side and uses (something similar to) turbolinks to
             | make it look fast. But generating additional types for
             | SomeDataType like ViewSomeDataType etc - my gut feeling
             | tells me these should be implemented trough type classes
             | instead. New data types shouldn't be generated for cases
             | like this.
             | 
             | Disclaimer: I've only looked at the docs of IHP, but this
             | was what it looked like it was doing.
        
       | revskill wrote:
       | I spent 1 year to focus on learning Haskell. It's a brain-hacking
       | language, too hard to master. But in the end, i've got some nice
       | basics on doing functional programming the right way.
       | Immutability, composable abstraction lies in the heart of a
       | maintainable software i'll produce.
        
       | unnouinceput wrote:
       | Quote: "GHC, the most commonly used Haskell compiler, produces
       | extremely fast executables, especially when compared against
       | other languages commonly used for application development, such
       | as PHP or Python"
       | 
       | Really? You comparing apples with oranges? Why not, if you're at
       | the step of comparing compiled versus interpreted languages,
       | compare it with Java too?
       | 
       | Now, do the same comparison versus C++, let's see who wins when
       | talking about speed.
        
       | johndoe42377 wrote:
       | Unfortunately, the Haskell ecosystem has been ruined (well,
       | almost) by unnecessary, redundant abstractions and narcissistic
       | idiots who pushes them.
       | 
       | I recently tried to compile haskell-language-server and stack
       | from sources. 157 and 168 (or something) dependencies, full of
       | redundant esoteric bullshit, compat packages, lifted crap, etc.
       | It is even worse than J2EE where it was the same redundant
       | wrapping and indirection, but brain-dead straightforward verbose
       | crap.
       | 
       | To use Haskell correctly, like the classic xmonad and similar
       | projects, requires discipline, knowledge and good taste for just
       | right abstractions, like Go stdlib or Scala3 standard library.
       | 
       | Yes, it doubles development time, which must be spent on
       | understanding anyway, but fast food fp code, full of redundant
       | abstractions, is a worst nightmare to maintain.
        
         | bryal wrote:
         | > narcissistic idiots
         | 
         | Right back at ya
        
         | marcosdumay wrote:
         | > To use Haskell correctly, like the classic xmonad and similar
         | projects, requires discipline, knowledge and good taste for
         | just right abstractions
         | 
         | Hum... Knowledge and an acquired taste, yes. You'll need those.
         | Discipline not. Discipline is exactly what Haskell doesn't
         | require.
        
         | hardwaresofton wrote:
         | This article might be a bit overeager and overzealous, but how
         | you use haskell is up to you -- don't use those underlying
         | packages that disgust you if you don't like them. Haskell
         | offers benefit at every level of abstraction. There are many
         | ways to write Haskell and you do _not_ need a bunch of the
         | higher level stuff. 99% of the time you are just fine with the
         | data modeling (simple Algebraic Data Types) and type classes,
         | along with a cursory understanding of monads via  "do"
         | notation.
         | 
         | This comment reads like someone seeing the worst of J2EE, and
         | going back to C++. I'd characterize haskell as having the type
         | system that Java wishes it did.
         | 
         | Why are you trying to judge how haskell should be written for
         | your use case by looking at haskell-language-server, stack, and
         | xmonad? Those are the domains of haskell experts -- one is a
         | language server, the other is one of the pre-eminent build
         | tools, and the other is tiling manager.... Are any of those
         | your use-case?
         | 
         | There are real problems with haskell, and forcing you into
         | complexity is not one of them -- a steep learning curve (for
         | _certain_ concepts), hard to debug space leaks, and a
         | relatively small ecosystem are the biggest issues.
        
           | throwaway894345 wrote:
           | > how you use haskell is up to you -- don't use those
           | underlying packages that disgust you if you don't like them
           | 
           | These kinds of arguments are particularly lazy. Of course,
           | Haskell's ecosystem is not so large that it's trivial to find
           | a well-maintained, high-quality version of a library that
           | meets one's other criteria. Programmers of a particular
           | language are at the mercy of that language's ecosystem.
           | 
           | This line of reasoning reminds me of how C++ programmers
           | would deflect criticisms of problematic features by arguing
           | that one could use only the features that one wanted (thereby
           | effectually creating or curating their own sub-language) and
           | only choosing dependencies that were equally written in that
           | sub-language. So easy!
        
       | fooyc wrote:
       | Sounds like "Haskell is cool because it is typed, and it is the
       | only typed language I know"
        
       | [deleted]
        
       | wombat23 wrote:
       | What I'd like to understand: When/why does one choose Haskell
       | over other functional languages e.g. F# or OCaml?
       | 
       | It looks to me like they would satisfy the same points that the
       | article makes.
       | 
       | Edit: just did a quick comparison of the last 2 SO developer
       | surveys, and it looks like Haskell "replaced" F# in their
       | popularity ranking last year.
        
         | nudpiedo wrote:
         | all them are equally competent languages. F# with corporative
         | support and a giant ecosysten, ocaml being very fast and
         | portable and haskell being very... special and pure.
        
           | wombat23 wrote:
           | Thanks for your reply!
           | 
           | I see the corporate aspect of F#, but can you elaborate on
           | what you mean by "special" about Haskell?
        
         | chriswarbo wrote:
         | Haskell's laziness and purity can make it a bit trickier to use
         | constructs that are common in ML-like (or Scheme-like)
         | languages, like mutable variables. This nudges Haskell
         | libraries in a slightly different direction, e.g. making more
         | use of control structures like monads, arrows, continuations,
         | etc. which authors in other languages wouldn't reach for so
         | readily. This has an effect on the ecosystem, since people want
         | their systems and libraries to be compatible with each other's
         | APIs.
         | 
         | The result is that "the Haskell way" can seem a little more
         | intimidating than the more "pragmatic" approach of MLs.
         | 
         | (I write this as someone who writes a lot of Haskell, and
         | dabbles in StandardML!)
        
       | FlyingSnake wrote:
       | I simply don't get the hate this article is getting, are some HN
       | readers really that bad at reading comprehension? The authors
       | clearly mention it is "our first choice" and then they go on to
       | present their findings with great clarity. Nowhere do they
       | evangelize Haskell like other language like Rust for example. I
       | never see such comments on threads on other languages, even
       | though some of articles posted are of subpar quality.
       | 
       | In the end the insecurities and failures of snarky commentators
       | don't matter to others who are in the arena solving real problems
       | in production with an unsexy language.
        
       | coldtea wrote:
       | Why Haskell is our first choice for building production software
       | systems: a rationalization of our excitement to get to write
       | Haskell in production
       | 
       | Here, I've fixed the title
        
         | tome wrote:
         | Would you say that you've engaged in good faith with the point
         | the author was trying to make?
        
           | jamil7 wrote:
           | Eh, I kind of agree with the parent comment. The author
           | didn't bring up any compelling points that couldn't be found
           | in other modern languages (granted these likely borrowed from
           | Haskell). As an outsider to Haskell I was hoping for some
           | more concrete use cases for picking the language.
        
             | weego wrote:
             | Honestly there are no compelling arguments for picking
             | Haskell over other languages in the same domain.
             | 
             | Limited open-source to leverage, incredibly limited and
             | costly hiring opportunities, not that great tooling and
             | integrations.
             | 
             | Any upside you can sell from a pure programming point of
             | view (there are some very valid ones) pale in comparison to
             | the negatives it brings to your overall business.
        
           | FpUser wrote:
           | I've found article arguments incorrect - what they describe
           | as Haskell's features and more are easily available in other
           | languages as well. Strictly enforcing function style on the
           | other hand looks to me as un-feature. From my long experience
           | strictly enforcing any particular paradigm/style in
           | programming is amounts to plugging round holes with the
           | square pegs.
        
             | warcher wrote:
             | I'm a partisan, of course, but I always found ocaml to be
             | the practical choice for ML-style functional languages. All
             | the functional type-y goodness without being shackled to
             | it, you can let yourself off the hook if you need to, you
             | can just write a dang loop if that's what needs doing,
             | compiles down to native, just a good practical mix.
             | 
             | Other than Jane Street, nobody much uses it though, so
             | that's that.
        
           | coldtea wrote:
           | Absolutely
        
       | bsenftner wrote:
       | I'm at a technology research company that is primarily using C++
       | as the main company tool. The development team is small, and the
       | code is the result of 22 years of constant revision by PhDs. One
       | of our Never To Be Violated Rules, simply because the number of
       | hidden landmines is far to numerous, is template programming.
       | When generic programming is required we use a web language like
       | PHP where the type of something is contextual and one can be free
       | and loose and sloppy if they want. Between the two extremes of
       | our formal as fuck C++ base and the anything goes generic web
       | languages we maintain surprisingly high levels of productivity,
       | with very low bug counts. Having a tiny team helps, as we all
       | know the code based inside out.
        
       | fooyc wrote:
       | > Haskell programs have stellar performance, leading to faster
       | applications and lower hardware costs [...] PHP $244 [...]
       | Haskell $15
       | 
       | This is overlooking the cost of developers, which greatly
       | outweights the hardware's unless you are Facebook.
        
         | vp8989 wrote:
         | No it isn't, it's a simple matter of fact statement that
         | running code on runtime A appeared to be cheaper in terms of
         | hardware costs than runtime B.
         | 
         | The "overlooking" part you filled in yourself in bad faith and
         | bad reading comprehension, as the author actually does
         | acknowledge that the observed hardware savings are small
         | compared to the cost of hiring programmers.
        
       | kensai wrote:
       | Has anyone had a look or knows of production systems made with a
       | Haskell-like language named Curry? (https://curry-lang.org/)
       | 
       | Sounds a lot like Haskell with Prolog...
       | 
       | " Curry is a declarative multi-paradigm programming language
       | which combines in a seamless way features from functional
       | programming (nested expressions, higher-order functions, strong
       | typing, lazy evaluation) and logic programming (non-determinism,
       | built-in search, free variables, partial data structures).
       | Compared to the single programming paradigms, Curry provides
       | additional features, like optimal evaluation for logic-oriented
       | computations and flexible, non-deterministic pattern matching
       | with user-defined functions."
        
         | iso8859-1 wrote:
         | You can already have Prolog embedded in Haskell, using LogicT.
         | 
         | Here is the paper by Kiselyov:
         | http://okmij.org/ftp/papers/LogicT.pdf
        
         | chriswarbo wrote:
         | I've played with it, using the kics2 implementation. I made a
         | rough package for Nix, which might be useful if you have
         | problems installing it:
         | 
         | http://chriswarbo.net/git/warbo-packages/git/branches/master...
         | 
         | You might like the Mercury language too:
         | https://mercurylang.org/
        
         | tome wrote:
         | Tangentially, did you actually manage to make an HTTPS
         | connection to that site? I can only manage HTTP.
        
       | aardvark1 wrote:
       | This company looks to be a team of three (probably very smart)
       | engineers who build cool custom software for likely relatively
       | small clients. The software is likely only supported and modified
       | by them. In that scenario something like Haskell makes sense -
       | however once you need to scale your engineering footprint beyond
       | 5-10 people it becomes virtually impossible to rationalize using
       | a niche language like Haskell.
        
         | sesuximo wrote:
         | Also unclear how long they've been doing this... I'm unable to
         | find any info about provide projects other than very high level
         | blog style stuff
        
         | ivanbakel wrote:
         | What is that claim based on? Plenty of companies use Haskell to
         | great success scaling to well beyond 10 people. It may be a
         | niche language, but in a remote-working world, and with a truly
         | massive number of developers in the workforce, there still end
         | up being a sizeable number of professional Haskell developers
         | available to most companies.
        
       | Areading314 wrote:
       | It is absolute nonsense to say that using Haskell will improve
       | productivity or maintainability. There are problems like bad
       | libraries, complicated performance profiles, virtually no
       | developer adoption, limited ghc build targets, package
       | management, lack of tooling, slow compile times. Choosing Haskell
       | is likely a terrible choice despite the type system, which seems
       | to be its only advantage.
        
       | waterheater wrote:
       | According to a friend who worked there, Kitty Hawk's flying car
       | flight controller is written in Haskell. Gotta love those MIT
       | researchers.
        
       | jcelerier wrote:
       | > Many programmers encounter statically typed languages like Java
       | or C++ and find that the compiler feels like an annoyance. By
       | contrast, Haskell's static type system, in conjunction with
       | compile-type time checking, acts as an invaluable pair-
       | programming buddy that gives instantaneous feedback during
       | development.
       | 
       | the reason they "find that the compiler feels like an annoyance"
       | is because their first exposure to Java / C++ is in school where
       | they have an assignment due for tonight and the compiler won't
       | stop banging pages of errors about std::__1::basic_string<char,
       | std::__1::allocator<char>> and what the fuck is that shit I just
       | want to make games !!11!1!
       | 
       | In contrast Haskell is often self-taught which gives a very
       | different set of incentives and motivations.
       | 
       | As a mostly C++ programmer making sure that I get compiler errors
       | as often as possible by encoding most preconditions in the type
       | system is one of the most important part of my job and make the
       | language very easy to use when you use an IDE which allows to
       | click on an error and going to the right place in the code.
        
         | slifin wrote:
         | "acts as an invaluable pair-programming buddy that gives
         | instantaneous feedback during development."
         | 
         | This is the key bit, this is called static analysis, you don't
         | need a type system in your language to do this, and you don't
         | need to force doing it at compile time
         | 
         | Most developers appear to conflate the two, uncoupling static
         | analysis and type systems would benefit most workflows
        
           | mrkeen wrote:
           | > you don't need to force doing it at compile time
           | 
           | What assembly instructions should the compiler emit if you
           | write sum ["foo", "bar"] ?
        
         | corty wrote:
         | Annoyance about C++ errors isn't only about the error occuring.
         | With me, it is predominantly about the utter unusability of the
         | error messages. C++ has postprocessors you can use to get your
         | 20 page STL errors down to a few lines just by reversing the
         | expansion the compiler did to show you mere mortal something
         | that you might recognize as your code instead of template-
         | cthulhu.
         | 
         | Haskell has such situations as well, but usually far less
         | verbose. Getting something to typecheck because you wrote down
         | something incompatible uninferable still sucks. But far less
         | than C++.
        
           | ashtonkem wrote:
           | Haskell error messages are far less verbose, but I find them
           | hard to read. What makes it worse is that often the error
           | message involves a lot of deeply nested types that were
           | hidden from me before by library writers using an alias. So
           | I've had a lot of "where did _that_ come from?" moments.
        
             | brundolf wrote:
             | I had this problem when being onboarded into a TypeScript
             | codebase recently. Unfortunately I don't think there's a
             | technical solution to it: the type system simply won't stop
             | you from making types that are way too complicated (unless
             | you use a language like Go where the type system is
             | intentionally lobotomized, which obviously comes with its
             | own problems).
             | 
             | We're used to avoiding complexity when it comes to _logic_
             | , but maybe there's less awareness when it comes to
             | _types_. Maybe what we need is to have a bigger
             | conversation around that so people realize it 's something
             | that needs to be on their radar.
        
               | chc wrote:
               | The thing is, these types aren't usually complex in the
               | way that logic is. Complex logic generally means lots of
               | loops and conditions and such, maybe shared mutable
               | state. Linear code that just calls a series of
               | independent functions one after another is not generally
               | considered complex, even though it may ultimately result
               | in the execution of lots of code. What generally leads to
               | these confusing errors is just simple types composed end-
               | to-end. The problem is that while compilers are good at
               | picking out the specific part of a function that's
               | causing problems, they generally can't do the same thing
               | with types, so it's kind of like if every time you got an
               | exception, the entire module source was pinpointed as the
               | problem.
        
               | 91edec wrote:
               | Typescript needs some work on displaying type error
               | messages, often the last line is all that needs to be
               | read.
        
               | brundolf wrote:
               | Type systems are really good for detecting
               | contradictions; they're much less good at figuring out
               | which piece should be _different_. For any given type
               | error, there may be half a dozen different changes to the
               | code that would resolve it in different ways. Type
               | systems often have no real way of guessing the user-
               | intent there. There are loose heuristics, like... an
               | explicit return type is more likely to be intentional
               | (and therefore correct) than the type of the local value
               | that 's being returned. But I'm not aware of any
               | formalism around this "ranking" of which types are most
               | likely to be unintentional. Maybe we need one.
               | 
               | The only immediate solution I can see is to keep types
               | simple enough that the user can fit the entire relevant
               | type-space in their head (and in the IDE dialog!), so
               | that they themselves can determine which part is actually
               | "wrong" (as opposed to just contradictory).
        
           | MaxBarraclough wrote:
           | I don't agree here. As someone who's only ever dabbled with
           | Haskell, I found its error-messages pretty cryptic, no better
           | than C++. Perhaps they make more sense to someone with
           | significant Haskell experience.
           | 
           | For what it's worth, I believe modern C++ compilers give much
           | better error messages than older ones.
        
           | pjmlp wrote:
           | Not only do modern compilers give better error messages (with
           | room for improvement still), it is possible to make use of
           | enable_if and if constexpr/static_assert to give proper error
           | messages for templates, and when C++20 gets widespread
           | enough, concepts.
        
             | dkersten wrote:
             | Modern clang (usually, there are edge cases) gives pretty
             | good error messages over all. And like you point out, if
             | you use constexpr you get even better messages. Hell, I
             | watched some cppcon videos over the weekend and learned
             | that clang can even detect out of scope access of
             | temporaries when in a constexpr (but not otherwise sadly),
             | and also that in many cases, a lot more of a program can
             | probably be constexpr than we might think.
             | 
             | The talks were by Jason Turner, who has an ARM emulator
             | implemented entirely as constexprs and a test suite that
             | runs at compile time (so if it compiled, the tests passed).
             | Obviously for actually interacting with it, its not running
             | at compile time, but the logic has the ability to run at
             | compile time, which is pretty cool.
        
               | pjmlp wrote:
               | Jason Turner has very cool talks, check the C64 one if
               | you still haven't watched it.
        
               | dkersten wrote:
               | I haven't watched that one yet, thanks for the
               | recommendation! I'll give it a look tonight.
        
             | dmitriid wrote:
             | I personally call it "old school" vs "new school".
             | 
             | "Old school" is asically the programming languages that
             | originated in the 70s-80-90s. An incorrect but an
             | illustrative way to describe error messages for them is
             | "The programmer needs to suffer". They are any combination
             | of cryptic, terse, complex, exposing internal machinery of
             | the compilers and linkers etc. There are many reasons for
             | this: computers were not powerful enough to afford better
             | code analysis, parsing, backtracking etc; the users of the
             | tools also knew the tools and could tinker with them etc.
             | 
             | "New school" is from late 2000s on. I usually say it
             | started with Elm. Clear messages pinpointing the exact
             | problem, solutions to problems inside error messages, error
             | clarity as one of the priorities in language/compiler/tool
             | design.
        
               | pjmlp wrote:
               | Some of it caused by too much reliance on tools like
               | yacc.
               | 
               | Category grammars were much better but more resource
               | demanding, just like proper ASTs instead compiling as one
               | goes.
               | 
               | Ironically there were already some attempts to Smalltalk
               | like tooling for C++ back then, but again as you mention
               | too much resource constraints.
        
           | Rompect wrote:
           | In contrast, Rust's compiler sometimes gives suggestions for
           | changes which can often just be copied.
        
             | emteycz wrote:
             | That's not entirely true. It gives suggestions in the cases
             | where the C++ compiler does too. There are more than a few
             | very cryptic errors you can encounter with Rust. I like it
             | though, just needs more work.
        
               | 3836293648 wrote:
               | Depends on the compiler. In my very limited experience
               | I've found that Clang is far superior to GCC in this
               | matter (but rustc is better still, apart from iterator
               | errors)
        
               | srean wrote:
               | I am curious about which GCC, G++ version you have in
               | mind. Clang definitely took the lead, but by GCC caught
               | up and I prefer GCC's do Clang. But even I am behind the
               | bleeding edge quite a bit so not sure how things stand
               | now.
        
               | leshow wrote:
               | It's been a while since I used C++ but I have never seen
               | suggestions of the same quality that the rust compiler
               | produces. Do you have a link that shows the error
               | messages you're talking about?
               | 
               | For sure though, not every error has a great message and
               | some can be cryptic. But those cases are relatively rare
               | these days IMO
        
             | jhayward wrote:
             | I'm always puzzled by people who see this as somehow a good
             | thing.
             | 
             | If the Rust compiler can figure out what the type should
             | be, why doesn't it just do the cross-function inference,
             | and leave the complicated nested implications which only
             | obscure the intent and effect out of it?
             | 
             | If having the programmer specify types is an important
             | check on the correctness of the code that is written, how
             | is blindly copying, without understanding some 60+
             | character type specification string from an error message
             | going to help demonstrate correctness? All it does is make
             | two sections "consistent". It isn't something the
             | programmer understands or specifies as a type check.
        
               | lostcolony wrote:
               | Because the computer being right 90% of the time when
               | something is ambiguous doesn't preclude the programmer
               | from understanding it (while still providing them a best
               | guess at their intent for those times they don't), but
               | DOES mean that the program doesn't assume the wrong thing
               | that remaining 10%.
        
               | Rusky wrote:
               | I am not sure where you got the idea that Rust error
               | message suggestions lead to blindly copying 60+ character
               | type specifications. They tend to be much more localized
               | and understandable in my experience.
        
               | jhayward wrote:
               | I got the idea by following the Rust tutorials and then
               | making 'simple' programs, seeing the errors, going to
               | Rust resources and getting the advice 'just cut and paste
               | the expected type'. The expected types generally had 6-8
               | ':'s, and three to four deep nested type specifiers.
        
               | steveklabnik wrote:
               | > why doesn't it just do the cross-function inference
               | 
               | It could! This is an explicit design choice. There are a
               | few different reasons. They're all sort of connected...
               | 
               | In general, Rust takes the position that the type
               | signature is the contract. If you inferred the types on
               | function signatures, changing the body of your function
               | could change the signature, which means that breaking
               | changes are harder to detect. It also leads to "spooky
               | action at a distance" errors; I could change a line of
               | code in function A, but then the compiler complains about
               | the body of some unrelated code in a totally different
               | part of the codebase, because that changed the signature
               | of function A, which changed the signature of function B,
               | which is called in function C. My error shows C is wrong,
               | but I made a mistake in the body of A. That's confusing.
               | Much nicer to say "Hey you said the signature of A is X
               | but the body is Y, something is wrong here."
               | 
               | I am gonna handwave this one slightly because I don't
               | fully remember all of the details, but full program
               | inference and subtyping is undecidable. Rust doesn't have
               | subtyping in general for this and other reasons, but
               | lifetimes _do_ have subtyping. I am sure this would get
               | ugly.
               | 
               | Speaking of getting ugly, Rust is already criticized
               | often for compile times. Full program inference would
               | make this much, much worse. Again with that changing
               | signatures issue, cascading signature change would cause
               | even more of your program to need to be recompiled, which
               | means that bad error message is gonna take even longer to
               | appear in the first place.
               | 
               | I think there might be more but those are the biggest
               | ones off the top of my head.
        
               | leshow wrote:
               | > I am gonna handwave this one slightly because I don't
               | fully remember all of the details, but full program
               | inference and subtyping is undecidable. Rust doesn't have
               | subtyping in general for this and other reasons, but
               | lifetimes do have subtyping. I am sure this would get
               | ugly.
               | 
               | Correct. Haskell is the only language I know of with
               | globally decidable type inference, and uses the similar
               | hindley-milner method as Rust... but no doubt some of
               | Rust's language features can break global inference. In
               | Haskell, many common language extensions can also break
               | global inference.
               | 
               | I think if Haskell was written today they probably
               | wouldn't pick global inference as a goal, Haskell "best
               | practice" types the function boundaries in the same way
               | that Rust enforces.
        
         | cogman10 wrote:
         | I run into the same thing with Java.
         | 
         | Code that always upsets me is something like `Map<String,
         | Object>` where a concrete type would work so much better (and
         | faster).
         | 
         | Using a statically typed language, the most important thing you
         | can do is USE IT. Let the type system save you from problems.
         | Encode whatever you can in the types.
         | 
         | Bypassing it by casting always causes headaches.
        
         | mlthoughts2018 wrote:
         | I find the compiler an annoyance in Haskell just as much as C++
         | - it just forces me to write more code (more liability) and
         | leads to overly rigid type system designs, like modeling
         | behavior with classes or traits/type classes. I've only found
         | these ways of writing software to be universally worse than
         | simple module-oriented programming, writing C-like code in
         | languages like Python or Ruby and only selectively using C
         | extensions for isolated cases where speed provably matters.
         | 
         | Compilers do not offer compensating benefits, like catching
         | bugs or ensuring behavioral correctness, that justify all the
         | extra rigidity, slowness, and especially liability of all the
         | extra code (even in Haskell).
        
         | Blikkentrekker wrote:
         | I learned both _Haskell_ and _Rust_ self-taught an still find
         | the latter 's type system a bit of a cage for it's lack of
         | higher kinded types, frankness be.
         | 
         | I know not much of _Java_ , but my sentiments concerning _C++_
         | are even worse.
         | 
         | I do not regularly program in _Haskell_ and far more often in
         | _Rust_.
        
           | platinumrad wrote:
           | "I don't know much about this thing but I don't like it, and
           | I know even less about this other thing and I like it even
           | less!"
           | 
           | For what it's worth, C++ has HKTs in the form of template
           | template parameters, making it possible to write, e.g., monad
           | transformers, which cannot be done in Rust, last I checked.
           | Now as for whether you'd actually want to do this in a
           | production codebase...
        
           | marcosdumay wrote:
           | Rust metadata (not just types) have an habit of getting in
           | your way.
           | 
           | It is all for good reason, you can't ditch the GC and have
           | control over the memory structure without the compiler
           | complaining about details here and there. But fixing those
           | strings versus slices and iterator type mistakes is really
           | annoying.
        
         | dsign wrote:
         | Amen to that. I love dearly both C++ and Haskell, but I
         | remember those times when I wanted to cry because the C++ error
         | message broke the OS clipboard when I was trying to copy it to
         | a text editor so that I could write a program to analyze it and
         | find which "const" didn't match in the jungle of type names. I
         | have never had that situation with Haskell.
        
           | Vosporos wrote:
           | Oh dear :o
        
         | js8 wrote:
         | Actually, the reason why I found static typing annoying in the
         | past (and why I felt more productive in Python) were the types
         | are really low level (missing basic things like tuples) and
         | lack of type inference. You have to repeat the type
         | information, a lot. And also you have to declare lot of
         | intermediate data structures.
         | 
         | In Python, this became easier and one could focus on the data
         | transformations, thinking about the code a level higher.
         | 
         | But then I learned a bit of Haskell 5 years ago, and with type
         | inference, this problem goes away. So it convinced me back to
         | benefits of static typing. (Although I still feel the most
         | productive in Python, their library APIs are IMHO unmatched in
         | any language. But Haskell is catching up.)
        
           | KingOfCoders wrote:
           | I've joined several companies, and getting into a Python code
           | base was the most difficult one, because of the lack of typed
           | method parameters. It was easier with Java and better still
           | with Scala - same for Typescript vs. Javascript. I would be
           | interested, is your Python experience green field or joining
           | a large project? (just wanting to know, not implying anything
           | on your part).
        
             | gameswithgo wrote:
             | there are controlled studies supporting this idea the
             | function parameters not having types slows down
             | productivity
        
               | tome wrote:
               | It would be helpful if you linked them ...
        
             | js8 wrote:
             | It was an experience on my personal projects, cca 20 years
             | ago. That's when I started using Python and it really felt
             | more powerful than C++ (and Java) back then. Then around
             | 2008 I became interested in Common Lisp, and then later I
             | made the choice to learn Haskell instead of Clojure. It
             | took me a while before actually getting where is the
             | improvement in Haskell and functional programming. This was
             | all for my own personal projects, which are small programs.
             | 
             | I would still recommend against using Python on a big
             | project. Funny thing, I remember talking to my boss (a
             | mainframe programmer) in 2010, when I solved something with
             | a script in Python, that I wouldn't use it in production,
             | but it's great for small things. Forward to 2020, plenty
             | people use it in products. Maybe the Haskell will be the
             | same, you also have many people today saying "well this is
             | good for experiments but I wouldn't write a product in it".
        
             | neutronicus wrote:
             | I worked on a large-ish C++/Python codebase and touching
             | the Python parts was always extremely frustrating for me.
             | 
             | The lack of .h files alone is a huge grievance for me - I
             | had to scroll past definitions even to know names and
             | arities of class methods, read constructors to know what's
             | in class members.
             | 
             | SciPy was nice enough for turning data into a picture,
             | though.
        
               | supergarfield wrote:
               | > The lack of .h files alone is a huge grievance for me
               | 
               | That's an interesting point... Besides C and its
               | derivatives, and OCaml, do other languages have separate
               | definition files? It seems like newer languages, even
               | statically typed, normally don't.
               | 
               | I suspect the reason is that you have to duplicate all
               | definitions, which seems like rote work. It also feels
               | less necessary with IDE tooling: IDEs I know have a view
               | for all definitions in a file.
        
               | mumblemumble wrote:
               | They don't, but, at least in object-oriented languages,
               | much of overall experience is easy enough to replicate
               | with formal interfaces and coding standards.
        
               | KingOfCoders wrote:
               | I thought the nice thing about Modula-2 was that you
               | could browse through interface files to understand some
               | code and then go into implementations.
        
               | mumblemumble wrote:
               | It's true, but there are so many ways to skin that cat.
               | Smalltalk, for example, gives an even more fluid way to
               | browse at a high level and then drill in, and it doesn't
               | (necessarily) have source code files in the first place.
        
             | jim-jim-jim wrote:
             | I had the exact same experience: being a new employee at
             | companies A and B, with large Python and Scala codebases
             | respectively. At company B it was far easier to get on
             | board and start writing code, and it has remained easy.
             | Trying to make sense of Python was truly demoralizing, and
             | a significant part of why I left company A.
        
             | wassenaar10 wrote:
             | > getting into a Python code base was the most difficult
             | one, because of the lack of typed method parameters
             | 
             | Yup, this is probably my main issue with Python. I love
             | writing it when I'm working on personal projects, having to
             | read massive Python code bases at work feels unnecessarily
             | tedious due to how much work you have to do sometimes just
             | to find out the type of something.
        
             | dehrmann wrote:
             | > getting into a Python code base was the most difficult
             | one, because of the lack of typed method parameters
             | 
             | One place I worked used to be a Python shop, but had
             | migrated most of its services to Java. Chatting with one of
             | the engineering leads for a large Python system that had a
             | lot of business logic, he said where Python actually fails
             | to scale is lines of code and developers because lack of
             | types makes it harder to reason about and harder to make
             | changes safely. This obviously changed now that type
             | annotations are a thing.
        
             | mumblemumble wrote:
             | I bounced off of Python a few times before finally taking
             | to it (at a time when I had no choice). I honestly believe
             | that this situation has improved since Python 3.5 or so,
             | purely on the basis of improved standards of documentation,
             | including many more libraries adding type hints to their
             | public interfaces.
             | 
             | I've recently been back to Clojure, and it's the same old
             | aggravation again. It seems that, oftentimes, the only way
             | to know what arguments a function is prepared to accept is
             | to already know what arguments a function is prepared to
             | accept.
             | 
             | I don't want to come across as being too down on dynamic
             | typing - I'm currently in the process of trying to get my
             | company over to Python by any means necessary. What I
             | really want to challenge is the idea, popular in many
             | dynamic typing circles, that static types just get in the
             | way. They can also serve to communicate essential
             | information. If you aren't communicating that information
             | through type annotations, then it's absolutely essential
             | that you do it by some other means.
        
               | ithrow wrote:
               | _I don 't want to come across as being too down on
               | dynamic typing - I'm currently in the process of trying
               | to get my company over to Python by any means necessary._
               | 
               | Curious, from what and why? ML?
        
             | mattnewton wrote:
             | For new python work that might grow, I highly recommend
             | pytype annotations. It's not perfect but it's as close to
             | the best of both worlds that I have ever seen in
             | production.
        
           | mehrdadn wrote:
           | > You have to repeat the type information, a lot.
           | 
           | Nope you don't, that's what typedefs are for. They're
           | underrated for sure though. People don't use them nearly as
           | much as they should. They're incredibly valuable for avoiding
           | precisely this problem.
        
             | msla wrote:
             | Shifting topics a bit, typedefs don't allow me to write
             | generic code. Templates do, but templates bring in their
             | own problems, in addition to not being expressive in the
             | right ways: I can have an array of T, but I can't specify
             | that T is Numeric?
             | 
             | The fact C++ doesn't have Numeric but instead has int and
             | long and unsigned and long long and float and double all
             | off on their own is another problem: The compiler knows
             | enough about them to have complex promotion rules but
             | doesn't know enough to allow me to refer to all of them
             | under one name in my code.
        
               | mehrdadn wrote:
               | You're asking for the impossible. What you want is
               | precisely what templates are, but you also want them to
               | not be "templates" for... some bizarre reason.
               | 
               | > I can have an array of T, but I can't specify that T is
               | Numeric?
               | 
               | Sure you can. If you have C++20 concepts:
               | template<class T>       concept Numeric =
               | std::integral<T> || std::floating_point<T>;
               | template<Numeric T>       T twice(T x)       { return x +
               | x; }
               | 
               | Or if you're on a C++11 compiler:
               | template<class T>       typename std::enable_if<
               | std::is_arithmetic<T>::value,         T>::type twice(T x)
               | { return x + x; }
        
               | jcelerier wrote:
               | the C++ 20 version can be simplified a bit to:
               | Numeric auto twice(Numeric auto x)         { return x +
               | x; }
        
               | mehrdadn wrote:
               | Probably not a good idea since the caller won't know what
               | the return type is at that point, and the return type
               | would become dependent on the implementation, which
               | breaks function abstraction.
               | 
               | And imagine what would happen when you get a few more
               | 'auto' variables in the return expression. Suddenly your
               | return type will depend on the _implementation_ of your
               | _callees_. And the code can then quickly become
               | impossible to understand.
               | 
               | auto is overused.
        
               | jcelerier wrote:
               | > Suddenly your return type will depend on the
               | implementation of your callees
               | 
               | Why would that be a problem ? It's super common in
               | templates and has never troubled me the least
        
               | mehrdadn wrote:
               | It might be common practice but it shouldn't be. There
               | are _lots_ of reasons this is a bad idea; here 's just a
               | sampling:
               | 
               | 1. "My return type is whatever I happen to return"
               | circumvents the ability of the type checker to ensure
               | correctness.
               | 
               | 2. More generally, the purpose of a specification (a
               | function declaration in this case) is to declare what is
               | required of a compliant implementation, and to provide a
               | way to check the validity of that implementation. But
               | when you make the types all become auto-deduced, you're
               | basically reducing the specification to a ~ _shoulder
               | shrug_ "it does whatever it does" ~. That defeats much of
               | the point of the type-checker.
               | 
               | 3. Moreover, as I alluded to in the comment, it quickly
               | becomes near-impossible to separate the definition from
               | the declaration, whether that's because you want to hide
               | it or because you want to compile it separately. It seems
               | like a minor thing when (as in the example) the return
               | value doesn't depend on types inferred from other
               | callees' return values, but as soon as that ceases to be
               | true, you suddenly tie together the implementations of
               | multiple functions. At that point, your functions lose
               | much of their power to abstract away anything, since as
               | soon as you change the return expression for one
               | function, it has the potential to break code in the the
               | entire chain of callers. (!)
               | 
               | 4. Templates end up getting re-instantiated far more
               | often than they need to be (which can slow down both the
               | compilation and the runtime efficiency). You almost
               | certainly don't want 'return 0' and 'return (size_t)0' to
               | result in duplicate instantiations, for instance.
               | 
               | 5. Issue #4 can also result warnings/errors/bugs, since
               | now you have a function that returns a different concrete
               | type than you likely intended, which can result in
               | everything from spurious warnings (signed/unsigned casts,
               | for instance) to actual bugs (later truncation of other
               | variables whose types were inferred incorrectly as a
               | result).
               | 
               | 6. The code becomes difficult for a human to read too.
               | You now no longer have any idea what types some variables
               | are supposed to be. Not only does this hamper your
               | ability to cross-check the correctness of the
               | implementation itself (just as with the declarations, in
               | #1) but unless your function is trivial, this quickly
               | makes it harder to even understand what the code _is
               | doing_ in the first place, never mind what it 's supposed
               | to do.
               | 
               | 7. Proxy types become impossible to implemented, since
               | they won't undergo the intended conversions anymore.
               | 
               | I can come up with more, but hopefully this gets the
               | point across.
        
               | msla wrote:
               | Bah. Leave it to the latest versions of C++ to show me
               | up.
        
               | dkersten wrote:
               | That's the point though, isn't it? To improve on areas
               | that were lacking in older versions. It can be hard to
               | keep up, though!
        
               | mehrdadn wrote:
               | It's not just the latest version though? C++11 could
               | already do what you wanted.
        
               | MaxBarraclough wrote:
               | _edit: I see mehrdadn beat me to it. I 'll leave this
               | here anyway._
               | 
               | > I can have an array of T, but I can't specify that T is
               | Numeric?
               | 
               | This is what type-traits and 'concepts' are for, right?
               | 
               | > The compiler knows enough about them to have complex
               | promotion rules but doesn't know enough to allow me to
               | refer to all of them under one name in my code.
               | 
               | This is what _std::is_integral_ gives you.
               | 
               | https://en.cppreference.com/w/cpp/types/is_integral
        
             | nicoburns wrote:
             | That doesn't stop you having to type e.g.
             | 
             | String foo = "bar"; String baz = foo;
             | 
             | The `String`s can be completely avoided in languages with
             | type inference because it's obvious that a string literal
             | is a string.
        
               | oblio wrote:
               | Java now has (limited) type inference, bar. As does C++,
               | auto. They're limited but they remove a lot of tedium.
        
               | mehrdadn wrote:
               | I thought the complaint was about the logic duplication,
               | not the extra keystrokes. If you want type inference you
               | already have auto. If you want to minimize your
               | keystrokes, you're using the wrong language to begin
               | with, whether there's type inference or not. C++ is
               | designed for writing software robustly, not quickly. (<--
               | This is not a trivial or obvious statement btw. It took
               | me several years to grasp this. And I viewed C++ from an
               | entirely different perspective when it finally sunk in
               | for me that I would appreciate C++ much more if I decided
               | to make minimizing keystrokes a non-goal.)
        
               | secondcoming wrote:
               | > If you want type inference you already have auto
               | 
               | or auto&&. Did you really intend to make a copy?
        
               | mehrdadn wrote:
               | You probably did intend it to be a copy if you're binding
               | it to a variable and need it to be non-const (like in the
               | example)!
        
               | secondcoming wrote:
               | Ah, but you knew that because that's how the code was
               | written!
               | 
               | If it was instead                   String foo = "bar";
               | auto baz = foo;
               | 
               | you don't know for sure. But the code compiles so it
               | obviously ok!
        
               | mehrdadn wrote:
               | No, I'm saying even in that case you know it was intended
               | to be a copy. If you wanted that to be a reference then
               | you'd either (a) just do the obvious thing which is to
               | just use the original variable name instead of creating a
               | new variable out of the blue for no reason, (b) leave a
               | comment explaining why you're not doing the
               | aforementioned obvious thing, or (c) use a self-
               | explanatory variable name to provide the explanation
               | instead of a comment.
        
               | UweSchmidt wrote:
               | Is it really that painful to write "String" each time?
               | You spend at least a fraction of a second anyway to
               | verify that you're writing the right thing, to reconsider
               | if you should use an object or constant or refactor the
               | function to work with a Boolean instead of a naked
               | string; why is writing out the type such a big deal
               | everytime this topic comes up?
               | 
               | I remember my first attempts at programming and being
               | annoyed that I can't add a string and an int; ever since
               | that little bit of housekeeping of using types made sense
               | to me and I can clearly see how it eliminates entire
               | classes of errors.
        
               | silluk wrote:
               | To me it's not the trivial cases like this that make type
               | inference useful. It's when you get longer types like
               | `Arc<Mutex<HashMap<String, String>>>`. Granted, that
               | could be solved with a `type` declaration (or `typedef`
               | in C++) but it's still convenient to be able to say: `let
               | mut x = Arc::new(Mutex::new(HashMap::new()));` and let
               | the compiler figure out the rest based on usage.
        
               | wtetzner wrote:
               | > Is it really that painful to write "String" each time?
               | 
               | I find it more painful to read code that has too many
               | type annotations. I also find it painful to read code
               | that has too few, so I'd argue there's a bit of an art to
               | it.
               | 
               | But languages that have type inference but allow type
               | annotations at least allow you to try to hit that
               | balance.
        
               | leshow wrote:
               | > I remember my first attempts at programming and being
               | annoyed that I can't add a string and an int; ever since
               | that little bit of housekeeping of using types made sense
               | to me and I can clearly see how it eliminates entire
               | classes of errors.
               | 
               | Type inference doesn't make these errors go away.
               | 
               | And about your other point, it's unfair to look at just a
               | simple case of writing "string" or not as the only thing
               | inference provides. Although I'd argue that leaving out
               | types where possible helps readability-- it's really the
               | more elaborate cases or intermediate steps during a
               | longer transformation that inference helps with. Not to
               | mention the fact that inference in closures is also
               | really nice.
        
               | secondcoming wrote:
               | And it's my experience that that is only a benefit to the
               | person who wrote the code, and only for a short time.
               | 
               | Generally, I prefer being able to read a line of code and
               | understanding exactly what it does. If I need an IDE and
               | have to repeatedly try to find the definition of
               | something then, in my opinion, that's wasting my time.
               | 
               | C++'s 'auto' is really useful but it's over-used IMO. I
               | think that there's a belief that if you're not using
               | 'auto' everywhere then you're not writing 'modern' C++.
               | Just becuase your code compiles doesn't necessarily mean
               | it's correct.
        
               | corty wrote:
               | Code that specifies types instead of using auto is,
               | barring compiler bugs, usually less correct. The compiler
               | knows better than you what the type really is.
        
               | nicoburns wrote:
               | I find that types can reduce readability as well as
               | enhance it. They add noise and make it harder to
               | concentrate on the variable names which are often much
               | more important than the types which are often (but
               | certainly not always) obvious from context.
        
               | secondcoming wrote:
               | Interesting point.
               | 
               | I'd never have believed it myself, but find myself using
               | acronyms instead of variable names when the type allows
               | it.                   void foo(MyType mt, const
               | MyOtherType& mot);
               | 
               | It's the variable names that are the noise, types are
               | everything. And no, it's not Hungarian notation either in
               | case anyone suggests it!
               | 
               | However, it maybe doesn't work that well with things like
               | class member names. YMMV
        
               | mehrdadn wrote:
               | +1 for auto being overused. I always felt I was shouting
               | into the void (hah) by saying the same thing... it's nice
               | to see someone else agrees.
        
           | WraithM wrote:
           | I appreciate that you wrote that you "feel" more productive
           | with python. I 100% agree with this feeling at most scales of
           | code size, and the feeling matches reality at the small
           | scale. However, I've found that this feeling of productivity
           | doesn't match reality in the large. I use Haskell for
           | programming in the large despite this feeling of
           | unproductivity, because in fact, I am way more productive.
        
             | bcrosby95 wrote:
             | > in the large
             | 
             | At what point do you feel like this line is crossed? "In
             | the large" can mean different things to different people.
        
             | js8 wrote:
             | Just to clarify, I agree that Haskell can be more
             | productive than Python, I was talking about productivity of
             | Python (or, for that matter, Lisp) compared to C-like
             | languages of the era. But with Haskell's type inference,
             | the Python's advantage is lost (if we forget, for a moment,
             | extremely well-designed Python's standard library with
             | focus on convenience).
        
           | jcelerier wrote:
           | > the types are really low level (missing basic things like
           | tuples) and lack of type inference
           | 
           | how far ago was this in the past ? C++ had tuples and type
           | inference for ten+ years officially now - gcc 4.4 had it in
           | 2009
        
             | mjburgess wrote:
             | There's also the culture around the language to fold in.
             | 
             | A culture of writing code assuming inference and structural
             | typing is quite different than it merely being available.
        
               | sfg wrote:
               | So, OCaml or something?
               | 
               | Or has Haskell added structural typing?
        
               | mjburgess wrote:
               | Haskell is structurally typed...
        
               | tome wrote:
               | Hmm, what do you mean? Haskell is generally considered
               | nominally typed (or rather types introduced by its
               | newtype and data declarations are ...). "Structural
               | typing" typically refers to things like polymorphic row
               | types and polymorphic variants.
        
               | mjburgess wrote:
               | Sure, my mistake. I meant something looser.
               | 
               | Only that the types can be analysed structurally (ie.,
               | pattern matched).
               | 
               | In C++, etc. there's a "radical nominalism" in which the
               | type was very opaque, ie., encapsualated.
        
               | gpderetta wrote:
               | It is complicated. Templates do allow some form of
               | structural typing and the new-in-C++17 structured
               | bindings do allow for decomposing and inspecting types
               | (although this being C++ it is kind of awkward).
               | Structured bindings are expected to evolve into full
               | pattern matching in the future.
        
               | FpUser wrote:
               | I have zero problems using type inference, tuples, etc in
               | my code. Other developers I deal with and who do use C++
               | have no problems using those "novel" concepts either. So
               | I am completely at loss about what type of culture you
               | are talking about here. It looks like grasping at a straw
               | type of argument to me.
        
               | mjburgess wrote:
               | I'm talking about all libraries and books written since
               | it's development up until the early 10s; and of all those
               | teams, libraries, and code which are legacy.
               | 
               | Haskell has _never_ had a decades-long history of
               | 'compiler-oriented programming', ie., excessive
               | declarations, and so on.
               | 
               | The idea that C++ has a haskellish culture is patently
               | absurd, even if the vanguard regard itself as presenting
               | tending toward that direction.
        
               | FpUser wrote:
               | I am in no way implying that "C++ has a haskellish
               | culture". Neither I would consider it of any advantage.
               | All I said is that modern C++ programmers have no
               | problems using the concepts. There is plenty of those
               | that are used in gobbles of libraries as well. Sure old
               | libraries do not have it but so what?
        
             | thesz wrote:
             | C++ cannot have non-local type inference due to, you know,
             | object-oriented part of it.
             | 
             | This means that you cannot say something like this:
             | auto sepulka;       auto bubuka = zagizuka(sepulka);
             | 
             | Because if zagizuka's parameter is a structure or a class,
             | you have a selection of parents. On a contrary, you have a
             | selection of descendants of the result type of zagizuka()
             | for bubuka, each having their own copy or assignment
             | constructor.
             | 
             | [1] http://lucacardelli.name/Talks/2007-08-02%20An%20Accide
             | ntal%...
             | 
             | [2] https://en.wikipedia.org/wiki/Intuitionistic_type_theor
             | y#Mar...
             | 
             | [1] shows how hard it is to make right type system with
             | inheritance. I believe these slides mention 25 years of
             | collaborative effort. Compare that to [2] where it took 8
             | years to design intuitionistic type theory (1971-1979) by
             | mostly single person.
        
               | andrekandre wrote:
               | not that im advocating it per se, but couldnt you deduct
               | the tyope based on what `zagizuga()` does with `sepulka`?
               | 
               | for example                 def sepulka(zagizuga)
               | zagizuga.doSomething()         zagizuga.doSomethingElse()
               | 
               | would infer the type of zagizuga as some object that
               | implements two methods `doSomething()` and
               | `doSomethingElse()`... i think that should be doable (and
               | possibly extremely slow) right?
               | 
               | maybe i missed something...
        
               | gpderetta wrote:
               | C++ doesn't have type inference at all which I understand
               | requires constraint solving.
               | 
               | It has a much simpler type deduction system where the
               | type of an object is deduced from its initializing
               | expression, i.e. deduction always flows in one direction.
               | 
               | It is nowhere as powerful, but it does cover a lot of use
               | cases.
               | 
               | One advantage (in addition to the ease of implementation)
               | is that, except for circular definitions, there are no
               | undecidable cases and it is not necessary to restrict the
               | type system to prevent them.
        
         | portal_narlish wrote:
         | Strong point! As a non-CS engineering student learning C++ for
         | the first time, the compiler all but turned me off from wanting
         | to be a programmer. No one explained _why_ the compiler was
         | even there, it just seemed like an annoying hindrance stopping
         | me from getting good grades on the homework.
         | 
         | Fast forward a decade and I'm evangelizing statically typed FP
         | at conferences. The value of the compiler is redeemed after
         | self-teaching and learning the "Whys".
        
         | avl999 wrote:
         | > the reason they "find that the compiler feels like an
         | annoyance" is because their first exposure to Java / C++ is in
         | school where they have an assignment due for tonight and the
         | compiler won't stop banging pages of errors about
         | std::__1::basic_string<char, std::__1::allocator<char>> and
         | what the fuck is that shit I just want to make games !!11!1!
         | 
         | Well I can't imagine how much more annoyed they'd be when using
         | an interpreted language which lets the code run just fine but
         | then fails at runtime in mysterious and subtle ways requiring
         | hours of manually scanning though code and print statements
         | when the compiler would have caught a decent subset of those
         | errors with helpful messages about the exact line they need to
         | fix.
        
           | bird_monster wrote:
           | > Well I can't imagine how much more annoyed they'd be when
           | using an interpreted language which lets the code run just
           | fine but then fails at runtime in mysterious and subtle ways
           | requiring hours of manually scanning though code and print
           | statements when the compiler would have caught a decent
           | subset of those errors with helpful messages about the exact
           | line they need to fix.
           | 
           | You cannot get mad at errors you don't know about.
           | 
           | Also letting the user find and report the error allows you to
           | mark your tickets "done" and move on, which makes management
           | happy.
        
           | ZephyrBlu wrote:
           | In my experience, you quickly develop an intuition for where
           | things are going wrong with interpreted languages.
           | 
           | Ex: "Oh, cannot access property x of undefined? Something
           | must be going wrong in y object"
           | 
           | Python definitely feels a lot more helpful than JS though.
           | Can't speak for other interpreted languages like Ruby.
        
             | cjfd wrote:
             | The thing is, though, that you mostly only get errors for
             | code that is actually executed. So, your program is only
             | fully type checked when all code paths are executed. In the
             | case of python one can ameliorate this situation a bit by
             | using mypy. At my job I see very often code being broken
             | because, e.g., the signature of a function was changed but
             | not in all places and so on. Now somebody will say that the
             | IDE can solve that but these colleagues who are regularly
             | breaking the code are actually using IDEs and it somehow
             | still does not help. I have come to think that code that is
             | not compiled and/or otherwise type checked is just not very
             | serious and certainly not worthy of production
             | environments.
        
               | pansa2 wrote:
               | > your program is only fully type checked when all code
               | paths are executed.
               | 
               | The solution to this is to make sure that, during
               | testing, all code paths _are_ executed. And that's
               | something you should be doing anyway, to find bugs that
               | aren't type errors.
        
               | cjfd wrote:
               | I am all for high test coverage. One should not
               | underestimate the effort in that, though. Some time ago I
               | covered some two thousand lines of code completely in
               | tests. As in, all code paths, checking all side effects.
               | Kind of an effort in the spirit of "dealing effectivly
               | with legacy code" by Michael Feathers. They were quite
               | non-trivial and it took me about two months. Doing such a
               | thing may not always be feasible. Also if code is written
               | by others they may have covered fewer code paths in tests
               | than one would have liked. A type checker will check all
               | code paths but the tests that your predecessor failed to
               | write are not checking anything.
        
               | srean wrote:
               | You can think of the compiler for a statically typed
               | language doing exactly that at runtime for a subset of
               | potential errors -- the type errors. Some people claim
               | that they never make them and they may well be correct. I
               | do commit such errors so compiler is a friend, but a
               | pedantic friend.
        
               | willtim wrote:
               | That is impossible with almost all non-trivial software.
               | Testing proves only the presence of errors not their
               | absence.
        
               | neillyons wrote:
               | > Testing proves only the presence of errors not their
               | absence.
               | 
               | I've never thought of it that way, but that totally makes
               | sense.
        
               | dkersten wrote:
               | I've worked with Python codebases that had very extensive
               | test suites and I've still encountered many cases of bugs
               | slipping through that a static type check would have
               | caught. Its really hard to make sure tests are fully
               | comprehensive. About the best you could do is generative
               | property-based tests, but then the feedback loop is not
               | great as it may take minutes, hours, days or weeks for a
               | particular problem case to be generated, while the static
               | check would have caught it at compile time or even
               | interactively in your IDE.
               | 
               | I don't hate dynamic languages, but this is a pretty
               | major weak spot for them, in my personal opinion, and one
               | that's bitten me a number of times.
        
           | jcelerier wrote:
           | having just spent an hour over vscode live share with a
           | student who's learning javascript, I have a pretty good idea.
           | 
           | But I've worked with people who saw all compiler errors as
           | things of the devil and wanted to defer as much as possible
           | to runtime.
        
             | kungito wrote:
             | faculty helps students debug their code?? where?
        
               | LandR wrote:
               | At my Uni we had students from higher years do volunteer
               | time during lab sessions for lower year students. You
               | would just wander around the lab helping random people
               | who were stuck.
               | 
               | Sometimes there would be some proffessors there too to
               | help you out.
        
               | jcelerier wrote:
               | I'm in france haha. why wouldn't you help a student who
               | asks you kindly ?
        
               | xdavidliu wrote:
               | Parent is probably referring to situations where faculty
               | are too busy researching, writing grants, or just plain
               | don't feel like it, and tell students something like
               | 
               | "go play with it"
               | 
               | "look it up"
               | 
               | "google it"
               | 
               | "read the fudging manual"
               | 
               | Of course, there are many great faculty who _do_ care
               | greatly about teaching and always help students.
        
           | dan-robertson wrote:
           | I feel like it probably isn't worthwhile to litigate the
           | merits of static typing every time there is a HN post that's
           | vaguely adjacent to the topic.
           | 
           | For the amount people care about it, there isn't much
           | evidence in either direction. And most studies that do exist
           | are limited to small programs typically written by novices.
           | Yale's Singapore campus are going to be running two instances
           | of the same course in parallel soon, one in python and one in
           | ocaml. Perhaps that will provide a datapoint about learning
           | the languages but maybe there will just be a lot of selection
           | bias or library or environment or teacher differences. And
           | how easy it is to learn a language probably isn't the main
           | datapoint to care about anyway.
        
             | ernst_klim wrote:
             | > there isn't much evidence in either direction
             | 
             | Oh, I think there are great evidences, such as: dialyzer,
             | or ruby3 and python3 shifting towards type signatures
             | everywhere and gradual typing, or recent racket focus on
             | typed racket. Oh, and the rise of typescript of course.
             | 
             | I mean, I've abandoned Python years ago, and I was quite
             | surprised when I discovered python people are adding type
             | annotations everywhere.
             | 
             | Sure, gradual typing is not a strictly enforced as in
             | statically typed languages, but seems people are agree that
             | modularity and abstraction without type signatures is
             | painful in sufficiently large programs.
        
               | dan-robertson wrote:
               | What you have described is an anecdote rather than any
               | study that attempts to be impartial which is what I
               | really meant when I wrote 'evidence.' I'm sorry for not
               | being clear enough.
               | 
               | I don't feel like this anecdote is evidence because I
               | don't think it's inconsistent with the trend towards more
               | static types over the last 5-10 years or so. For this
               | anecdote to be convincing I would need to think that
               | programming language design happens because of carefully
               | thought out and researched decisions and quick feedback
               | as good languages are used and bad languages are dropped,
               | but I don't believe this.
        
               | ernst_klim wrote:
               | This is not an anecdote by definition, since these
               | languages represents quite a huge marketshare (and most
               | of the rest langs are already statically typed).
               | 
               | Yes, this is not a sound rigid empirical proof, it's an
               | _observation_ (i.e. unlike the case of anecdotal, you can
               | measure the marketshare of user, how many do use dialyzer
               | or typescript, etc etc). We can 't simply ignore any
               | observations that are not scientifically rigid, otherwise
               | the whole edifice of philosophy or even some natural
               | sciences should simply perish.
               | 
               | I don't think you can just omit that. I'm a fan of
               | Lakatos here, if I have some observation, I think one
               | need at least as convincing evidence or more rigid one to
               | prove otherwise.
               | 
               | > because of carefully thought out and researched
               | decisions
               | 
               | I think it's a better evidence exactly because it's what
               | language users are asking about, and what large chunk of
               | language users choose to use when they got a choice. This
               | shows that quite a big share if not majority of
               | programmers value type annotations.
        
               | dan-robertson wrote:
               | > I think it's a better evidence exactly because it's
               | what language users are asking about, and what large
               | chunk of language users choose to use when they got a
               | choice. This shows that quite a big share if not majority
               | of programmers value type annotations.
               | 
               | To be clear, this is where I disagree. I don't want to
               | claim that people don't think hard about language design
               | or that users aren't asking for these features as I think
               | both of those statements are true. But I strongly
               | disagree that languages doing things (and those languages
               | being popular) is good evidence that those things are
               | good.
               | 
               | I think a lot of language design is driven by fashion (ie
               | keeping up with what similar languages are doing) and I
               | claim that this is a more convincing reason for python
               | having some gradual typing.
               | 
               | I think large number of people is moving to/from from
               | python for gradual typing in aggregate, and I don't think
               | it's happening on the margin either. I think any wise
               | decisions about languages are more likely to be driven by
               | practical considerations (what do people know, what are
               | they used to, what can people be hired for, what
               | libraries are available, what platforms are supported,
               | what performance is required, and so on).
               | 
               | Just because python has a large market share, it doesn't
               | mean it's users are supporters of gradual typing, it just
               | means that they thought python was a good idea when they
               | first started using it and they haven't justified the
               | cost of changing to something else. The users didn't
               | choose gradual typing they just chose "upgrade the
               | language to the next version"
               | 
               | Even if I agreed with your claim that many users asked
               | for gradual typing, I don't agree that in aggregate users
               | ask for things that will be good for them or good in
               | general. Maybe users are just trying to figure out a way
               | to say "we want our programs to be less buggy" and think
               | this might help. I think there are better examples in
               | programming language design of what can happen if you
               | keep giving users what they are asking for.
        
             | Guthur wrote:
             | It would if python actually encouraged runtime coding.
             | 
             | In my opinion dynamic programmers need to embrace the
             | runtime environment and use it as part of their development
             | methodology. Unfortunately most popular dynamic languages
             | have woeful runtime environments.
        
               | sfg wrote:
               | So, Common Lisp and Smalltalk?
               | 
               | Any others?
        
               | Guthur wrote:
               | I'd imagine some Scheme environments are good as well,
               | like Dr Racket.
        
               | andrekandre wrote:
               | yep, i was going to say the same thing, the biggest issue
               | with dynamic vs static is maybe people are missing the
               | point:
               | 
               | dynamic languages (like smalltalk) were designed for live
               | coding where the results are immediate, when that is
               | broken and coding is done in a "dead" environment of
               | course dynamic typing will cause problems that arent
               | caught until runtime... but the original idea was one
               | shouldnt have had to wait until runtime in the first
               | place!
        
       | jrh206 wrote:
       | Haskell is nice and all, but I'm not a huge fan of this take. I
       | can't help but think that many of the arguments boil down to
       | something like 'you can write types so that the compiler checks
       | things for you' (not a quote), whilst the author disregarded the
       | Java/C++ compiler as "an annoyance" (a quote). The rest of the
       | article is mostly a comparison between Haskell and
       | PHP/Python/JavaScript, and most laid out benefits boil down to
       | static typing.
       | 
       | Sure, Haskell's type system is nicer, and the error messages are,
       | I'm sure, more helpful (although the Java/C++ ones make sense
       | when you learn what they mean).
       | 
       | There is an example of domain modelling in Haskell:
       | type Dollars = Int              data CustomerInvoice =
       | CustomerInvoice             { invoiceNumber :: Int             ,
       | amountDue     :: Dollars             , tax           :: Dollars
       | , billableItems :: [String]             , status        ::
       | InvoiceStatus             , createdAt     :: UTCTime
       | , dueDate       :: Day             }              data
       | InvoiceStatus             = Issued             | Paid
       | | Canceled
       | 
       | The syntax is nice (ish, CustomerInvoice is a bit ugly), and
       | terse. But, I've seen this a million times in Java, and that
       | works fine.
       | 
       | Quote:                 Modeling domain rules in the type system
       | like this (e.g. the status of an invoice is either Issued, Paid,
       | or Canceled) results in these rules getting enforced at compile
       | time, as described in the earlier section on static typing. This
       | is a much stronger set of guarantees than encoding similar rules
       | in class methods, as one might do in an object oriented language
       | that does not have sum types. With the type above, it becomes
       | impossible to define CustomerInvoice that doesn't have an amount
       | due, for example. It's also impossible to define a InvoiceStatus
       | that is anything other than one of the three aforementioned
       | values.
       | 
       | All of this is table stakes in Java/C++ too.
       | 
       | Other brief rebuttals:                 Haskell has a large number
       | of mature, high-quality libraries
       | 
       | No way this beats Java. I don't know the C++ ecosystem well, but
       | I assume C++ wins too.                 Haskell enables domain-
       | specific languages, which foster expressiveness and reduce
       | boilerplate
       | 
       | Be careful what you wish for.                 Haskell has a large
       | community filled with smart and friendly people
       | 
       | I think at the end of the day Haskell just feels fun to write, if
       | you're the sort of person that likes it. That's fine. But I don't
       | think going all-in on Haskell is the right call for most
       | companies.
        
         | chriswarbo wrote:
         | > the author disregarded the Java/C++ compiler as "an
         | annoyance" (a quote).
         | 
         | To be fair, the context of that quote is:
         | 
         | > Many programmers encounter statically typed languages like
         | Java or C++ and find that the compiler feels like an annoyance.
         | 
         | I think this is a fair statement, although it would _also_ be
         | fair to say  "many Java and C++ programmers find their compiler
         | errors useful". I'd guess these two camps would remain _mostly_
         | the same when using Haskell.
         | 
         | You're right that most of the article is roughly comparing a
         | good example of static types (Haskell) against a bad example of
         | dynamic types (PHP).
         | 
         | > I've seen this a million times in Java, and that works fine.
         | 
         | My biggest problem with Java (and the JVM) is the existence of
         | `null`: it completely undermines type signatures. In the above
         | Haskell example we "know" (see caveat below) that a `myInvoice
         | :: CustomerInvoice` is a `CustomerInvoice`, whilst in Java a
         | `CustomerInvoice myInvoice` might be a `CustomerInvoice` or it
         | might be `null`; likewise `myInvoice.billableItems` is a
         | `[String]` in Haskell, whilst in Java it might be a
         | `List<String>` or it might be `null`; in the former case, each
         | element might be a `String` or it might be `null`.
         | 
         | Caveat: Haskell values are lazy by default, so errors may only
         | get triggered when inspecting some deeply nested value; in that
         | sense we might say that a Haskell expression of type `T` might
         | be a `T` or might be an error (known as "bottom"). We certainly
         | need to keep that in mind, but one nice thing about bottom is
         | that it can't affect the behaviour of a pure function (we can't
         | branch on it). In that sense returning a value containing
         | errors, which are later triggered, is practically equivalent to
         | triggering the error up-front (pure expressions have no
         | inherent notion of "time", unlike imperative sequences of
         | instructions). The interesting difference is that we can also
         | use such values _without_ triggering the errors, iff the
         | erroneous part is irrelevant to our result ;)
         | 
         | Having all types nullable by default makes 'proper' null-
         | checking incredibly verbose, not to mention tricky; the
         | alternative is to cross our fingers and hope our assumptions
         | are right. What makes this frustrating is that such checks are
         | exactly the sort of thing that computers can help us with, and
         | type systems are particularly well suited for! Hence the
         | presence of `null` cripples Java's type system in a way which
         | can't be worked around (without essentially layering a
         | separate, null-less type system on top to check for nulls!).
         | 
         | Also note that the presence of null causes every domain model
         | to collapse. Let's say we want to write a conversion method,
         | e.g. from `CustomerInvoice` to `Document`, and we don't want to
         | worry so much about `null`: hence we write in our javadoc that
         | as long as the given CustomerInvoice contains no null values,
         | this method will never return null; let's say we throw a
         | NullPointerException in those invalid cases. Great, our users
         | now have fewer edge-cases to worry about; they don't have to
         | check for null, and they don't have to catch
         | NullPointerException if their input is correct.
         | 
         | Except, once we start implementing our method we find it needs
         | to call some other helper method, e.g. `statusToTable`; if
         | _that_ method returns a null result, we would be unable to
         | construct the `Document` value that we promised. What can we do
         | in that case? We promised we wouldn 't return `null`, so maybe
         | we throw a NullPointerException? If we do that, those calling
         | our method might get a NullPointerException even if they gave
         | valid input! We might throw a different exception instead, like
         | AssertionError, but the effect would be the same. Hence we _can
         | 't_ guarantee to our callers that we don't return null (or some
         | equivalent that they must deal with, like NullPointerException
         | or AssertionError); that, in turn, means _they_ can 't provide
         | such guarantees to their callers, and so on. At any point, we
         | might get a null (or equivalent exception), and the whole house
         | of cards comes crashing down.
         | 
         | Maybe we trust that helper method _doesn 't_ return null, but
         | how can we know? Maybe we check its documentation or source
         | code to see whether it might return null; but we find that it
         | calls other methods, so we have to check those, and so on. If
         | we do this, we would also have to pin our requirements to the
         | precise versions of the libraries that we checked. In case you
         | couldn't tell, that process is essentially manual type checking
         | (for a very simple system with two types: 'Null' and
         | 'AnythingElse').
         | 
         | Of course, this is sometimes inherent to the problem, e.g. if a
         | HashMap doesn't contain the entry we need then there's nothing
         | we can do. However, most code _doesn 't_ have such constraints
         | (except perhaps out-of-memory), but there's no way to tell that
         | to Java (in mathematical language, Java weakens every statement
         | to admit trivial proofs).
        
         | dgb23 wrote:
         | The claims in the article sound weak, because they communicate
         | in an informal and natural way.
         | 
         | "Haskell's type system is more expressive than X and Y" is a
         | strong claim and can be proven by showing that X and Y need to
         | compose run-time workarounds for a given property that can be
         | checked statically in Haskell.
         | 
         | "Functional Programming reduces the surface area for Bugs" is a
         | strong claim and can be proven by showing that a single mutable
         | reference strictly introduces a set of possible bugs that were
         | not possible before and that these bugs cannot be checked in
         | language X.
         | 
         | It is kind of annoying that these discussions often seem
         | superficial, cultural or partisan, when in fact they could be
         | much more rigorous.
         | 
         | Now, If we assume or find these claims to be true we can
         | finally proceed with the real discussion: What are the costs
         | and benefits of these properties in a given setting?
        
           | arcturus17 wrote:
           | > "Functional Programming reduces the surface area for Bugs"
           | is a strong claim and can be proven
           | 
           | Is there really a formal proof or Software Engineering paper
           | that proves this?
           | 
           | I was told this in my FP class in university, but it pretty
           | much sold to me as gospel.
           | 
           | In practice I agree with the statement - I certainly feel
           | there's an inherent "cleanliness" to FP.
           | 
           | But I also feel that the argument is not only about program
           | correctness; many people ultimately conflate it with
           | developer productivity. And here's where I feel that things
           | fall apart a bit: I feel as if sometimes it's much quicker to
           | do things with state, so maybe the time you save debugging is
           | time you add elsewhere?
        
             | nix23 wrote:
             | >Is there really a formal proof or Software Engineering
             | paper that proves this?
             | 
             | Yes (page 7):
             | 
             | https://arxiv.org/pdf/1901.10220.pdf
        
             | Geminidog wrote:
             | Intuitively you can derive that this is true informally
             | past just an overall feeling.
             | 
             | It's simple really. Functional programming is just
             | imperative programming without one feature: mutability.
             | Thus if functional programming is just regular programming
             | with a reduced feature set it means it has the same error
             | surface area as regular programming minus the surface area
             | of errors caused by mutability. Hence by proof the error
             | surface area is smaller.
             | 
             | Now think of of all the errors caused by initializing a
             | variable as null and changing it later rather then
             | immediately initializing an immutable variable with the
             | correct value and you can intuit just how big the error
             | surface area actually is.
        
             | dgb23 wrote:
             | > Is there really a formal proof or Software Engineering
             | paper that proves this?
             | 
             | I wonder if there is one such formal proof as well.
             | 
             | Intuitively it is trivial: functions a are a subset of all
             | procedures, state can introduce unique bugs, these bugs are
             | not found in functions, so you're dealing with a subset of
             | all possible bugs.
             | 
             | Another intuition is this: By introducing state you
             | increase complexity. A procedure in isolation is not
             | necessarily referentially transparent, but a function is.
             | You cannot reduce the procedure with it's evaluation at any
             | given point in time, because it is 'connected' to the
             | surrounding program via that state. Now you'd have to show
             | that increased complexity introduces unique bugs.
             | 
             | I'm simply not equipped (yet) to make such claims, but I'd
             | love to hear from experts on these matters. I know that you
             | can formally verify stateful programs, so it is likely not
             | an issue of what is _possible_. But I damn sure know it is
             | much easier to reason informally about functions than about
             | procedures, except if the procedure merely has local state.
             | 
             | > And here's where I feel that things fall apart a bit: I
             | feel as if sometimes it's much quicker to do things with
             | state, so maybe the time you save debugging is time you add
             | elsewhere?
             | 
             | I can only speak for myself here, but yes certain
             | algorithms are more intuitive if implemented imperatively.
             | But I found that the set of these algorithms shrink over
             | time by getting used to FP. Vice versa there are also
             | algorithms that are much more easily written with
             | functions. Then there is core idiom of the language you're
             | using. If it is imperative OO, then writing functional
             | programs can sometimes feel cumbersome and less readable.
             | 
             | There are many factors that may or may not apply as well.
             | For example functions are easier to compose and decompose,
             | since they are by definition simpler. However imperative
             | procedures are sometimes easier to read "from top to
             | bottom", because they enable a more real-world-y
             | mechanical/visual mental model.
        
         | willtim wrote:
         | > But, I've seen this a million times in Java
         | 
         | Perhaps when Java gets record types, sealed classes, pattern
         | matching and other features. But right now, Domain Modelling in
         | Java (and C++) is _really_ painful compared to a higher-level
         | language like Haskell.
        
       | jjice wrote:
       | Haskell seems extremely neat, and I do like the ML family for
       | compiler development, but Haskell just seems like such a steep
       | learning curve. The amount of operators I've seen boggles my
       | mind, are they user defined? Is there a good way to learn Haskell
       | that preferably skips over some common functional concepts?
        
         | lallysingh wrote:
         | I'll put the learning curve around the same level as C++, with
         | the qualifier that most of what you learn aren't parts of the
         | language, but patterns and formalisms you can use in any
         | language.
        
       | darksaints wrote:
       | Okay, so this is admittedly snarky but we've seen this sort of
       | blog post so much that it has practically become an Onion
       | article: Why Haskell Is Our Secret Weapon, by Startup You've
       | Never Heard Of.
       | 
       | And then when someone points out that nobody knows who they are
       | or what they've built, we get commenters talking about how
       | company X, Y, and Z are also using Haskell. And those claims also
       | come up short...most of them can't say where or how it is being
       | used because they don't know...just that at some point in the
       | past, someone emails were exchanged between
       | someone@bignamecompany.com and someone@haskell.org, and now there
       | is a piece of copy on the Haskell website that disingenuously
       | claims _BigNameCompany is powered by Haskell!_. Who cares how
       | pervasivly it is used...if someone writes a config parser with
       | Haskell, all of a sudden we can claim that BigNameCompany would
       | fall over on its face if Haskell wasn 't there protecting it.
       | 
       | Come on. Nobody cares that Haskell is your secret weapon if
       | you've never overcome an opponent with it. Or built an entire
       | profitable company on its back. All these types of posts do is
       | fake an authority so you can jump straight to your fallacious
       | argument by authority.
       | 
       | If you want to argue the merits of your favorite language, _then
       | do it_. Don 't make us sit through an argument about how your
       | language makes you special when you aren't even noteworthy enough
       | for a 10 sentence Wikipedia blurb. There are a lot of valid and
       | powerful technical arguments in this article, but they're ruined
       | by framing them all around the premise that we care about how it
       | makes you and your startup special.
        
         | jimbokun wrote:
         | > Okay, so this is admittedly snarky but we've seen this sort
         | of blog post so much that it has practically become an Onion
         | article: Why Haskell Is Our Secret Weapon, by Startup You've
         | Never Heard Of.
         | 
         | But occasionally it pays off in a really big way.
         | 
         | Like WhatsApp cashing out for $19 billion, on a product they
         | never could have scaled with so few engineers without Erlang.
         | 
         | Like Viaweb and Common Lisp, where Paul Graham says the
         | language allowed them to move much faster than their
         | competitors. One anecdote was about talking on the phone to a
         | customer reporting a bug, and actually fixing it on the live
         | system and asking the customer to try again, and the customer
         | was shocked to find it now worked.
         | 
         | Like ITA, who created the best in class flight search system in
         | Lisp and then sold to Google.
         | 
         | Every once in a while, an unpopular but powerful technology
         | really is the secret sauce for a winning product.
        
           | yen223 wrote:
           | WhatsApp was sold to a company that made even more money off
           | the back of a PHP stack.
        
         | throwaway894345 wrote:
         | At least they don't have exactly one company that has had some
         | decent success with The Language in production, and were it not
         | for the evangelism of The Language Community, you wouldn't know
         | who the company was. And if you ask, "how does one do
         | multithreading in The Language?", The Community will shout at
         | you about how you don't really need multithreading and The
         | Company has been super successful and never once needed
         | multithreading and by the way multithreading will be a feature
         | in The Language Very Soon. :)
        
         | andai wrote:
         | I don't think the article warrants such a harsh reaction. Was
         | it the word "our" in the title? They're just writing from their
         | perspective.
        
         | warcher wrote:
         | I'm not really a haskell fan, but the lion's share of that
         | effect more that likely comes from the small sample size of
         | companies using haskell. Even if it were somehow superior,
         | there just are enough people trying it to be coming up with a
         | unicorn startup or two.
         | 
         | Now, the lack of skilled haskell programmers on the other hand,
         | that's a pretty scary proposition if you're starting a company
         | and may find yourself riding on a rocket, needing as many able
         | hands as you can possibly find.
        
       | dmitriid wrote:
       | I dislike Haskell. But this article goes out of its way to make
       | the worst possible case for Haskell imaginable.
       | 
       | > Many programmers encounter statically typed languages like Java
       | or C++ and find that the compiler feels like an annoyance. By
       | contrast, Haskell's static type system, in conjunction with
       | compile-type time checking, acts as an invaluable pair-
       | programming buddy that gives instantaneous feedback during
       | development.
       | 
       | Many programmers find that Java or C++'s static type system, in
       | conjunction with with compile-type time checking feels like an
       | annoyance. Unlike... the very same statement about Haskell?
       | That's... that's quite a weak claim, to say the least.
       | 
       | > a signature like Int -> Int -> Bool indicates that a function
       | takes two integers and returns a boolean value... this allows a
       | programmer reading Haskell code to look only at type signatures
       | when getting a sense of what a certain piece of code does. For
       | example, one would not use the type signature above when looking
       | for a function that manipulates strings, decodes JSON, or queries
       | a database.
       | 
       | So... Type signature `Int -> Int -> Bool` can be used for a
       | function that does any of the following things: manipulates
       | strings, decodes JSON, or queries a database? How does that make
       | it easier to deduce what a function does by "looking only at type
       | signature"?
       | 
       | > Another feature of a pure functional programming paradigm is
       | higher-order functions, which are functions that take functions
       | as parameters.
       | 
       | As in: available in almost any language these days, and not
       | exclusive to a "pure functional programming paradigm".
       | 
       | > One of the common development workflows we employ is relies on
       | a tool called ghcid, a simple command line tool that relies on
       | the Haskell repl to automatically watch code for changes and
       | incrementally recompile. This allows us to see any compiler
       | errors in our code immediately after saving changes to a file.
       | It's not uncommon for us to open only a terminal with a text
       | editor and ghcid while developing applications in Haskell.
       | 
       | As in: Modern IDEs don't require you to run external tools to
       | monitor your code for changes and highlight errors.
       | 
       | > a common refactoring workflow is to make a desired change in
       | one location and then fix one compiler error at a time until the
       | program compiles again.
       | 
       | As in: Modern IDEs let you do large-scale refactoring in one go,
       | at a press of a button.
       | 
       | > The type system can protect us from making mistakes when
       | changing the rules of our domain.
       | 
       | It can't. The example provided can't stop you from doing `case
       | status of Paid -> delete invoiceNumber`. You have to invest
       | significantly in a type-based DSL to prevent that from happening.
       | But then, who will test your DSL?
       | 
       | > Haskell enables domain-specific languages, which foster
       | expressiveness and reduce boilerplate
       | 
       | DSLs where all the rage 5-10 years ago. In reality, they are
       | overhyped and are used very sparingly, for obvious reasons: DSLs
       | are _languages_. They have to be designed, developed, maintained.
       | Errors in your DSL will most likely harder to find and debug than
       | in your regular program.
        
         | kreetx wrote:
         | To clarify the sibling, a signature of `Int -> Int -> Bool`
         | can't do any IO (so no connecting to databases, reading/writing
         | files, network requests), so it does tell you a lot about a
         | function.
         | 
         | It _can_ manipulate strings, decode JSON, but both of these are
         | either (immutable) values from enclosing scope, or created
         | within the function. But since they can 't be output anywhere
         | (because no IO) then they don't matter.
         | 
         | EDIT:
         | 
         | I'll just add a few more counterpoints.
         | 
         | Agreed that DSLs are difficult, and often not worth the
         | trouble. But if you do want to create a DSL, then haskell is a
         | good fit because of monads and monad transformer stacks - i.e
         | you can make the statement mean whatever you want it to mean,
         | and keep the effects in check with types.
         | 
         | The synergy between higher order functions with typed IO is
         | great, better than in other languages.
         | 
         | Agreed that IDE refactoring is convenient, and also refactoring
         | in other languages with static type checking the process is
         | similar to what they describe in the article, so no immediate
         | "pro" there.
        
           | dmitriid wrote:
           | > To clarify the sibling, a signature of `Int -> Int -> Bool`
           | can't do any IO (so no connecting to databases,
           | reading/writing files, network requests), so it does tell you
           | a lot about a function.
           | 
           | It doesn't help if it's `Int -> Int -> IO Bool`, for example.
           | Well, it does do IO, but other than that, who knows. Perhaps
           | it reformats the disc while CPU is idle :)
           | 
           | My main point though is that the article does a very poor job
           | of showing why Haskell is good at, well, anything, compared
           | to, well, anything.
        
             | kreetx wrote:
             | It's the fact that _it is_ `Int - > Int -> Bool` that
             | ensures you that the function doesn't do any random thing
             | (like doing something on the database). Combining non-IO
             | capable functions is quite helpful in reasoning about
             | programs. I.e if the function has `IO` in the result type
             | then exactly - "who knows". But with the fact that it
             | doesn't, _you do know_ that it doesn 't do anything other
             | than return the bool.
        
               | dmitriid wrote:
               | I mean. Really. That's what people hang up on?
               | 
               | The point for that particular gripe was this: "this
               | allows a programmer reading Haskell code to look only at
               | type signatures when getting a sense of what a certain
               | piece of code does."
               | 
               | Yes, IO tells that ... the function does some side
               | effects. And that's _it_. If your type signature is `Int
               | - > Int -> IO Bool`, it's just as useless as `Int -> Int
               | -> Bool`, and requires you to read the function to
               | understand what it actually does.
               | 
               | Is it helpful to see at a glance which functions produce
               | side effects and which don't? Yes, it is. Does it
               | automagically "allow a programmer reading Haskell code to
               | look only at type signatures when getting a sense of what
               | a certain piece of code does"? No, no, it doesn't. `...
               | -> IO Bool` may be launching nukes for all the
               | information you glean from its type signature.
        
               | Twisol wrote:
               | You don't get any information from `IO _` functions, but
               | that's the case with _every_ mainstream language, where
               | you have an implicit `IO` on every single function.
               | 
               | The benefit is not in `IO` -- its that its _absence_ on a
               | function tells you that it is heavily restricted in what
               | it can do.
               | 
               | If you want to go the _other_ way, you can concretely
               | model the kinds of effects you need parts of your
               | programs to do, and use that model instead of `IO`. Even
               | if you end up implementing it using `IO`, you know it can
               | 't use more than what your model exposes.
               | 
               | Both of these possibilities, while not truly _unique_
               | (see Agda, etc.), are absolutely rare-to-nonexistent in
               | mainstream languages. Effect modeling is a real shift in
               | perspective.
        
               | dmitriid wrote:
               | > You don't get any information from `IO _` functions,
               | but that's the case with every mainstream language, where
               | you have an implicit `IO` on every single function.
               | 
               | Indeed. And that's why I picked up on that particular
               | point in the article that I'm criticising. The article
               | chose to use those examples and those words and they _don
               | 't_ show anything beyond what other mainstream languages
               | have.
               | 
               | > If you want to go the other way, you can concretely
               | model the kinds of effects you need parts of your
               | programs to do, and use that model instead
               | 
               | Yes, you can. No, the article doesn't show that in any
               | way. Just to remind you how I started my comment:
               | 
               | --- start quote ---
               | 
               | But this article goes out of its way to make the worst
               | possible case for Haskell imaginable.
               | 
               | --- end quote ---
               | 
               | Does the article show "other models"? No. Does it even
               | try and show how to reason about a function by looking at
               | its type signature alone? Also, no. Would this article be
               | laughed into oblivion had it been about any other
               | language but Haskell? Yes, most likely.
               | 
               | > Effect modeling is a real shift in perspective.
               | 
               | Ah yes. Does the article talk about this? Does it show a
               | single example of this? No.
        
               | kreetx wrote:
               | Having a distinction of if something does IO or not is
               | quite important, and the fact that haskell has the
               | ability to encode it in types is what other languages
               | don't have.
               | 
               | Secondly, IO is just _one_ monad. You can build a more
               | granular one where you can separate filesystem, network
               | etc, and encode this into types (so you know at a
               | glance). You can 't do this in most other languages.
               | 
               | What are the types of things that are worth being hung up
               | on for a language for you?
        
               | dmitriid wrote:
               | Answered in a sibling comment:
               | https://news.ycombinator.com/item?id=25729423
        
         | bidirectional wrote:
         | > So... Type signature `Int -> Int -> Bool` can be used for a
         | function that does any of the following things: manipulates
         | strings, decodes JSON, or queries a database? How does that
         | make it easier to deduce what a function does by "looking only
         | at type signature"?
         | 
         | From this quote, it's easy to see you've not spent any time
         | actually using Haskell (others have explained what is actually
         | going on), so why do you dislike it? I cannot fathom having an
         | opinion either way on a language I don't know.
        
         | erdeszt wrote:
         | > So... Type signature `Int -> Int -> Bool` can be used for a
         | function that does any of the following things: manipulates
         | strings, decodes JSON, or queries a database
         | 
         | It can definitely NOT query a database(as that would be an
         | effect which would be visible in the type).
        
         | [deleted]
        
         | betareduce wrote:
         | I guess you haven't spend too much time with Haskell. Haskell
         | types especially generic ones are way more expressive and limit
         | your search quite a bit. The function Int -> Int -> Bool can
         | not reach for a database or anything other than the two Ints it
         | is given.
        
           | dmitriid wrote:
           | I guess I read the article and commented on what the article
           | was saying and claiming. Hence the introductory sentences at
           | the top of my post.
        
             | tome wrote:
             | Perhaps when you wrote
             | 
             | > Type signature `Int -> Int -> Bool` _can_ be used for a
             | function that does any of the following things
             | 
             | [My emphasis] you meant "can't". That could be one
             | explanation for the confusion that seems to have arisen
             | here.
        
           | magicalhippo wrote:
           | Why couldn't it be a function that queries a database, like
           | answering "on invoice x, does line y exist"?
           | 
           | Genuinely curious, not that familiar with Haskell, just
           | thought you could use something like parameter binding or
           | similar to construct functions like that.
        
             | uryga wrote:
             | if it has side-effects, it has to be something like
             | Int -> Int -> IO Bool
             | 
             | otherwise the type checker won't let you perform any side-
             | effecting operations
             | 
             | (btw Haskell's `IO Bool` would be spelled `IO<Bool>` in
             | C++/Java syntax)
        
               | magicalhippo wrote:
               | And there's no way to get rid of the IO then, presumably
               | (I mean otherwise I could have just used that as a
               | wrapper).
               | 
               | edit: So at work, just about every value depends directly
               | or indirectly on stuff that comes from files or from the
               | database. So would they all have to be wrapped by IO?
        
               | chriswarbo wrote:
               | As a concrete example, there's a nice function in
               | Haskell's standard library called `interact :: (String ->
               | String) -> IO ()`: https://hackage.haskell.org/package/ba
               | se-4.14.1.0/docs/Prelu...
               | 
               | Its argument is a function of type `String -> String` and
               | it returns an `IO ()`, i.e. an i/o action with a trivial
               | result. That action will call the given function on
               | contents of stdin, and writes its result to stdout. Or,
               | equivalently, we can think of `interact f` as
               | transforming a pure string-processing function `f` into a
               | stdio CLI.
               | 
               | Note that laziness (specifically "lazy IO") causes stdin
               | to be read 'on demand', giving us a streaming computation
               | without any extra work. Here's an example implementation
               | of 'wc':                   module Main where
               | import System.IO              main :: IO ()         main
               | = interact count              count :: String -> String
               | count input = show (length (unwords input))
               | 
               | Bonus: if we want to show off, we could implement 'count'
               | using function composition like this:
               | count = show . length . unwords
        
               | Twisol wrote:
               | In Haskell, you often build pure transformations, and
               | then _lift_ them into an effectful context. If I have a
               | function `String - > [String]`, say to parse a line of
               | CSV into its elements, I can lift that to `IO String ->
               | IO [String]` using the IO monad's `fmap`. And then I can
               | compose it with something hypothetical like `readLine ::
               | File -> IO String`, which actually reads the line.
               | 
               | The core logic of a program often doesn't need to care
               | deeply about state or system resources. Pure functional
               | programming is about writing as much as you can in this
               | "functional core", and then lifting the assembled pieces
               | of pipeline into the "imperative shell" (such as the IO
               | monad).
        
               | magicalhippo wrote:
               | Ok, so you make pure functions and turn them dirty, so to
               | speak. Makes sense.
               | 
               | In our case, almost all core code depends on various
               | parameters, which come from the database.
               | 
               | For example, GB recently left the EU so everything
               | involving GB is now processed under different rules,
               | except old stuff which has to be processed under the old
               | rules. Thus being part of EU or not is a date-dependent
               | database query (it already was, not the first time a
               | country's EU status has changed).
               | 
               | So if I get your explanation correctly, I'd code the core
               | logic as if these parameters were pure, side-effect free,
               | which would make the core logic side-effect free. In the
               | case above, I'd pass a function which maps a (pure) date
               | and string into a (pure) bool, to test for EU membership.
               | 
               | I'd then turn that whole thing dirty via the IO thingy,
               | passing "IO parameters" and receiving "IO results", so I
               | can pass it my EU test function which does a database
               | query.
               | 
               | edit: And I presume my "dirty" database-connecting
               | function can also mutate things, so it can do caching.
               | Don't want to hit that database too often.
        
               | uryga wrote:
               | > In the case above, I'd pass a function which maps a
               | (pure) date and string into a (pure) bool, to test for EU
               | membership.
               | 
               | i doubt you could make (or really, even want to make)
               | `checkEUMembership` pure, I'm guessing it'd involve a DB
               | lookup of some kind.
               | 
               | in general, you can't always "pull out all the IO" into
               | an only-pure-logic "core"; like if you want to look up
               | one thing and then look up another thing based on the
               | result of the first lookup. and that's okay!
               | 
               | i'm not going to write a whole monad tutorial, but using
               | an `IO Foo` is kind of like using a `Promise<Foo>`1; you
               | do stuff like this (in JS syntax):
               | getX(...).then((x) =>         getYForX(x).then((y) =>
               | foo(x, y)           // note - nested lambdas/closures,
               | `x` is closed-over         )       )
               | 
               | "do-notation" lets you avoid callback hell, similarly to
               | async/await.
               | 
               | ---
               | 
               | 1 Unfortunately, JS's Promise#then mixes two things:
               | 
               | * "dirtying" a pure function:
               | getNumberFromDB().then((x) => x*2)
               | 
               | which in Haskell would use                 fmap :: (a ->
               | b) -> IO a -> IO
               | 
               | * piping the result into another side-effecting function:
               | getNumberFromDB().then((x) =>
               | getNameForNumberFromDB(x)       )
               | 
               | which in Haskell would use the "bind" operator:
               | (>>=) :: IO a -> (a -> IO b) -> IO b
        
               | magicalhippo wrote:
               | > i doubt you could make (or really, even want to make)
               | `checkEUMembership` pure, I'm guessing it'd involve a DB
               | lookup of some kind
               | 
               | Well that was kinda the root of my question. The core
               | logic doesn't really care as such, as long as it could
               | determine EU membership somehow, but actual code would
               | have to use a DB lookup[1].
               | 
               | That of course spirals back to what would that really buy
               | you. You'd write code pretending it's pure while it
               | really isn't. I can see part of the appeal, but I can do
               | that in my current language.
               | 
               | Of course I don't get an error if I do something silly in
               | the middle of some otherwise "pure" module, so there's
               | that.
               | 
               | Anyway, illuminating. I enjoy thinking about these things
               | and challenging my self-taught ways. Thank you all for
               | your contributions, much appreciated!
               | 
               | [1]: An aside but, due to an error on the government
               | side, GB is part of EU today as far as _one_ of their
               | validation checks is concerned. So today only we have to
               | pretend along, for just that one field. This stuff is
               | fun!
        
               | uryga wrote:
               | > You'd write code pretending it's pure while it really
               | isn't.
               | 
               | in a way, it's the opposite! the point is you can't
               | pretend, you have to make impurity painfully explicit:
               | getTradeTax :: CountryId -> CountryId -> IO Float
               | --                                       ^ sirens
               | blaring, side-effect alert       getTradeTax ca cb = do
               | aInEu <- lookupEUMemberDB ca         bInEu <-
               | lookupEUMemberDB cb         if (aInEu && bInEu)
               | then (pure 15.00)           -- made up value
               | else getNonEUTradeTax ca cb -- another impure operation
               | 
               | there's the "IO" in the signature, and all the do-
               | notation `<-`, ie syntactic sugar for `>>=`, piping the
               | result into a callback. to use the Promise analogy again,
               | `x <- foo` is kinda like `x = await foo` (but more
               | general, bc Monads are cool)
               | 
               | > I can see part of the appeal, but I can do that in my
               | current language.
               | 
               | true, and i've seen IO-monad-alikes for Python and JS,
               | but most of the benefits come when every library you use
               | has to be explicit about impurity and there's a
               | typechecker enforcing it.
        
               | zvrba wrote:
               | But is _just reading_ from a database a "side-effect"? It
               | is non-deterministic, but it has no side-effects. So IO
               | jumbles together the two notions.
        
               | uryga wrote:
               | pedantically, talking to the database will involve
               | sending a request or some kind of IPC, all of which are
               | usually considered side effects.
               | 
               | [handwavy analogy alert]
               | 
               | people often call it "side-effects" as a shorthand. in
               | reality an expression being of type `IO Foo` mostly just
               | tells the compiler that order of execution matters (which
               | isn't the case with pure functions):                 do
               | print "a"          print "b"             -- obviously not
               | the same as              do print "b"          print "a"
               | 
               | and also that it can't eliminate common expressions:
               | do a <- readBytes file 100          b <- readBytes file
               | 100          doStuff a b            -- obviously not the
               | same as            do x <- readBytes file 100
               | doStuff x x
               | 
               | it's a way of enforcing ordering in a lazy language where
               | evaluation order isn't really defined.
        
             | ToJans wrote:
             | Haskell functions are pure, which means they can only
             | access/use what is in their parameters, so unless you pass
             | in some extra context (typically using a monad or an
             | effect), you do not have access to the "outside world".
        
               | magicalhippo wrote:
               | You can bind parameters though in Haskell, no?
               | 
               | I'm used to Boost.Bind and similar, so was thinking a
               | scenario where you bind the database connection parameter
               | and pass the resulting function to something else.
               | 
               | As the sibling pointed out though, I now get that the
               | result would be "tainted" so to speak.
        
               | johnday wrote:
               | A database connection would operate either in IO (the
               | generic "i am now talking to an unreliable outside
               | world") monad, or some more specific monad.
               | 
               | In this case you can think of a monad a bit like a
               | computational context. If one is not present, you simply
               | cannot[^1] instruct a Haskell program to perform those
               | operations in a type safe way even if you give it a valid
               | database connection identifier.
               | 
               | [1] Well, you can, but if you do you're explicitly taking
               | away all the safeguards that Haskell introduces, and it
               | would never pass code review.
        
       | thedonkeycometh wrote:
       | tldr; We love Haskell, that's why.
        
       | hardwaresofton wrote:
       | Haskell is an excellent language, and you are free to choose
       | _not_ to drown yourself in the most complex uses of it.
       | 
       | Haskell has the type system Java wishes it did, and half of the
       | reason languages like Rust are interesting is because they've
       | learned from Haskell (which is the _point_ of Haskell, a research
       | langage, though it happens to also be a pretty darn good language
       | for building practical things). Simple basic data types like
       | `Maybe t` and `Either l r` are such a revelation that you wonder
       | how you lived without them.
       | 
       | I've shared this anecdote before, but Option<T> in Java is an
       | example of the blub paradox[0], and discovering Haskell and
       | finding out about Algebraic Data Types (ADTs) and the Maybe type
       | cured my blub. The crux was this: Option<T>s seems to "infect"
       | any codebase you use it on, because you realize that anything can
       | fail and be null -- living in java land made it seem like it was
       | out of place it's actually Option<T> that is right -- if you
       | allow nullable types in your code base, or you do operations that
       | can fail, properly representing that failure is the right
       | decision.
       | 
       | Without over stating some of the best features of Haskell are:
       | 
       | - Compile time type checking (this cannot be understated) and
       | non-nullable types
       | 
       | - Expressive and simple data type creation via `data`, `type`
       | 
       | - An excellent system for attaching functionality and composing
       | functionality to data types via `typeclass`es and `Constraint`s.
       | 
       | - An emphasis on errors as values (unfortunately exceptions are
       | in the language too, but you can't really stop them from
       | existing)
       | 
       | - Forced delineation between code with side-effects and code
       | without (this results in some complexity if you come from a world
       | with side-effects everywhere and no control)
       | 
       | - Fantastic runtime system with good support for concurrency,
       | parallelism and shared memory management.
       | 
       | - Very easy refactoring (if you're not adding any
       | complexity/abstraction) because you can just change what you want
       | and let the compiler guide you the rest of the way.
       | 
       | Haskell has it's warts (hard to debug space leaks, relatively
       | small ecosystem, the ability to drown yourself and your team in
       | abstraction), but it's just about the most production-ready
       | research language I've seen.
       | 
       | Whether or not you like it, the likelihood it's already improved
       | your life in whatever language you're using is very high.
        
         | Twisol wrote:
         | You dropped this:
         | 
         | [0] http://paulgraham.com/avg.html
         | 
         | (Scroll to "The Blub Paradox", about a third of the way down.)
        
       | Kototama wrote:
       | Biggest problem I had with Haskell was once you know the language
       | you also need to learn a pile of extensions that any serious
       | project is using. Also there is a tendency in the community to
       | always look for the "best" (abstract) solution. It makes the
       | whole ecosystem fast changing.
       | 
       | I would prefer a more stable platform designed for engineers ,
       | something like Clojure but with types. Ocaml has a small
       | community and Scala brings unnecessary complexity with its
       | support for OOP.
        
       ___________________________________________________________________
       (page generated 2021-01-11 22:02 UTC)