5 ms·
PostgREST is written in Haskell and quite popular: https://postgrest.org/en/v7.0.0/ https://postgrest.org/en/v7.0.0/ Shellcheck has become a very important too
by Athas 6y ago
PostgREST is written in Haskell and quite popular: https://postgrest.org/en/v7.0.0/ https://postgrest.org/en/v7.0.0/
Shellcheck has become a very important tool to many people writing shell scripts: https://github.com/koalaman/shellcheck https://github.com/koalaman/shellcheck
GitHub's semantic analysis is written in Haskell: https://github.com/github/semantic https://github.com/github/semantic
I'm not sure why Pandoc doesn't count.
I think it is definitely the case that most examples of successful Haskell are technical programs of interest to hackers. I don't think that's much of a problem myself.
- ragnese 6y agoI think the key issue is not that successful Haskell programs are technical. I think it's that Haskell is not good for heavy-IO programs. I'm not sure how PostgREST works, but shellcheck and pandoc, for example, are really well suited for "IO on the edges" style: you feed bytes in once, and then at the very end you spit some other bytes out. Everything in the middle is parsing and transforming data. If you're writing some boring CRUD app, or a GUI program that makes a bunch of syscalls, Haskell sounds like a giant pain in the ass. From that POV, I think that Haskell's relative lack of popularity is perfectly fine. Not every language has to be maximally general.
- nightski 6y agoI used to write a lot of Haskell and tbh I find the idea of restricting IO to the edges of an application to be equally as important in traditional imperative programming languages as well. It's just good design, not a PITA. It seems to be a common view point that Haskell makes IO difficult. I actually personally found that it was more powerful because I was being more explicit about it. It also allowed for higher ordered functions to abstract common patterns in IO. The only difficulty in Haskell was not due to monads or type safety, but rather in getting my brain to understand lazy evaluation by default.
- ragnese 6y agoI agree that keeping IO sequestered is generally good advice. And it's something that I also do in imperative and OO languages as a rule of thumb. But having the type system signalling at IO is happening doesn't end up being useful in non-lazy languages where purity doesn't actually help an optimizer. I found this blog post to be kind of interesting: https://blog.ploeh.dk/2017/02/02/dependency-rejection/ https://blog.ploeh.dk/2017/02/02/dependency-rejection/ Skim that and then take a look at the back-and-forth in the comments. Sometimes going out of your way to write mostly pure (or just non-IO) functions can make your code more difficult to reason about. In my experience, you're sometimes left with two choices: either do a bunch of IO upfront that you might end up throwing away (if there is an `if` statement in your pure function that determines whether you need the result of some IO op), or pull out logic into the naughty impure edge of your program. If you do the former, you're wasting performance. If you do the latter, you're not actually fixing anything that pure functions are supposed to help you with, because you still have logic in impure functions. In my experience there are these edge cases where finding the cutoff between "the edge where I'm allowed to do IO" and the "pure business logic" is not that clear or easy. Also, as the old saying goes: monads don't compose well.
- nightski 6y agoHaskell doesn't force you to make the separation either (nor does it trivialize software design). You can write all your pure code in IO if that is what you'd prefer. I look at types as more of a way to communicate to others using my code as "here be dragons, this has side effects" or vice versa. The developer using your code doesn't just have to trust a comment block, they can see it directly in the types. I agree monad composition isn't amazing. When I was writing a lot of Haskell (I was working on real time 3d reconstruction algorithms from video feeds using camera input and OpenGL output) it wasn't a very large roadblock though. But effect type systems seemed like they might be cleaner. I don't have time to read through that article right away but I saved it for future reference - thank you for sharing.
- steve-chavez 6y agoIO at the edges also gives your program the Functional core, imperative shell[1] design by default. [1]: https://www.destroyallsoftware.com/screencasts/catalog/functional-core-imperative-shell https://www.destroyallsoftware.com/screencasts/catalog/funct...
- sfvisser 6y agoMost CRUD apps and UI still has IO on the outside pure/domain stuff on the inside. Most CRUD server handlers basically boil down to fetch and parse incoming HTTP request, decide to fetch some external resources (db/cache/service), prepare a response, and reply to the client. Fits the IO-on-the-outside model perfectly. React and friends have shown that UI views are mostly pure functions. Some local state and external resource can be fetched in some runtime hook and passed into your pure renderer.
- ragnese 6y agoFor the most simple CRUD apps, there is almost zero business logic. So your whole application is basically IO. What's the point of Haskell's IO type when every function will have to be IO? For the less simple apps, IO can be hidden behind interfaces for complex business logic. Here's an imaginary example: def getPriceForShoppingCart(product: Product, user: User, getDiscount: (User) -> Percentage): Price { if (user.isPremium) { product.price * getDiscount(user) } else { product.price } } How do we put the IO on the edges? Does this function just disappear and we have an `if` statement in our impure outer shell? That smells like business logic in the impure shell to me. Do we go ahead and call `getDiscount` in the outer shell and pass in the discount to the function? That also sucks because what if we made that trip to the database when we didn't need to (because the user is not a premium user)? I feel like every time I try to be religious about IO at the edges and not using impure dependency injection tricks, I end up running into a bunch of cases like this. On the other hand, if I stand back and look at a function like this objectively... It's easy to understand, it's still quite easily testable. What's the problem?
- marcosdumay 6y agoThis function is receiving a product and a user as arguments. Why would it do any IO? Anyway, CRUD does really not lead to clear "is IO"/"isn't IO" boundaries, and the business logic isn't a good candidate for separating from IO into a pure core. Instead, it is a great candidate for separating into a "with business data" context that is neither simple IO nor pure. On the implementation of that "with business data" context you will find plenty of opportunities to push IO to the boundaries of complex code that will become pure. But your intuition is correct, what you are missing is that the code can be broken on more dimensions than the ones you are assuming.
- fegu 6y agoThe Integrated Haskell Platform (IHP) open sourced at GitHub.com/digitallyinduced/ihp is one example of how to do crud in Haskell very efficiently.
- reikonomusha 6y agoI think those that you listed are genuine success stories, but “technical programs of interest to hackers” helps very little with broad adoption. Facebook also wrote parsers, analyzers, and linters in PHP, and those were deployed to production. PHP let you write these things, but also all of the cruddy stuff non-Hackers like to write. I am by no means advocating the use of PHP (even modern post-fractal PHP), but where’s a boring application that Haskell is a success in? You know, a little game you could download and have fun with? Or a billing system?
- przemo_li 6y agoAs a PHP developer who did some nice parser to get strict schema & data validation out of XMLs of potential fluid (over time) structure, I can assure you that PHP do not bring any ergonomic solutions to the table. It's possible and even very probable that PHP devs... stolen plenty of ideas from Haskell just to write "utility" libraries with witch they could write those parsers/analyzers/linters you are talking about :) However, I also can't see how PHP could be used to efficiently re implement that spam library Facebook developed. There whole promise lies on separation of effort into two teams: * spam engineers write pure code that happily merges data from different sources * backend engineers write integrations with Facebook systems and optimization passes over code spam engineers wrote to make sure that most optimal use of costly I/O was made PHP brings nothing, literally nothing to the table here. While Haskell have all the mechanisms already built in. Your argument about PHP sadly boils down to "its all Turing complete anyway".
- _query 6y agoHere's a "boring" haskell app: https://dill.network/ https://dill.network/ It's a vegan product scanner. You can find the story behind the project here: https://twitter.com/larsparsfromage/status/1321185935711735808 https://twitter.com/larsparsfromage/status/13211859357117358... Here's a "boring" internal management system: https://twitter.com/fegundersen/status/1325534608079941633 https://twitter.com/fegundersen/status/1325534608079941633 Disclaimer: Founder of digitally induced, the company that helps make boring things with IHP+Haskell :)
- 6y ago