9 ms·
Haskell: A Great Procedural Language
- RobotToaster 2y agoSomewhat tangential, but the only software I know of that's written in Haskell is ImplicitCAD https://implicitcad.org/ https://implicitcad.org/
- weikju 2y agoShellcheck is another useful one (linter for shell scripts) https://www.shellcheck.net/ https://www.shellcheck.net/
- tmountain 2y agoHaskell is an amazing type checker that’s occasionally used for writing software. ;-)
- thesz 2y agoThis thing is awesome! I tried it on couple of one liners and it found a couple of potential problematic points, one for each one liner.
- Vosporos 2y agoShellCheck is an essential part of my projects' CI, couldn't do without it!
- MaxRegret 2y agoDon't forget Pandoc!
- f1shy 2y agoI had no idea it was Haskell. So much for what I heard “no practical use”. Pandoc seems like very real life practical Application for me.
- sudahtigabulan 2y agoAnd Pandoc's author is not even a software professional. He's a philosophy professor. :^)
- tombert 2y agoI've said for awhile that Pandoc is one of the very few Haskell programs that isn't exclusively used by Haskell programmers. There are plenty of interesting Haskell programs (e.g. Xmonad, Darcs), but a lot of people explicitly use them because they're Haskell. Pandoc, on the other hand, is useful to pretty much anyone who has ever needed to convert documents. It's one of the first things I install on most computers.
- AlgebraFox 2y agohttps://simplex.chat/ https://simplex.chat/ Private messenger for desktop and mobile platforms. It's mostly written in Haskell except for UI.
- exe34 2y agoHaving a quick look through their repos, it looks like they don't use Haskell for the mobile platforms? > cpp-for-mobile > Template for cross-platform mobile app with native UIs and C++ core
- AlgebraFox 2y agohttps://github.com/simplex-chat/simplex-chat/blob/stable/flake.nix https://github.com/simplex-chat/simplex-chat/blob/stable/fla... Their flake.nix indicates they use Haskell to generate cross compiled shared library for Android, iOS, Mac, Linux and Windows. I am not expert in Nix but at high level I can see they are indeed using Haskell.
- exe34 2y agoah that makes sense thanks!
- internet_points 2y agoAlso the server backend for the Wire messenger https://github.com/wireapp/wire-server https://github.com/wireapp/wire-server
- FabHK 2y agoPity that Wire never took off. It combined all the advantages of messaging apps for a while (available on many platforms, e2ee, etc.). Goes to show that success is not determined by technology.
- ryandv 2y agoThe aura package manager for AUR, as well as the xmonad tiling WM.
- yehoshuapw 2y agohttps://hledger.org/ https://hledger.org/ hledger - a plain text accounting tool
- colordrops 2y agoXmonad, though most people have moved on to other window managers at this point.
- mbwgh 2y agoNot me, because I hate change!
- ulrikrasmussen 2y agoI still use it, it's the main reason I don't want to switch to Wayland. Everything looks and feels like it did 15 years ago, it's great!
- internet_points 2y agohttps://github.com/waymonad/waymonad https://github.com/waymonad/waymonad (no idea if it's usable)
- cap11235 2y agoThere are stronger reasons to avoid wayland. It's a protocol that manages to have all implementations slightly different, and creating an EGL context per the glxgears results in a hard crash, both with AMD and NVIDIA cards. I assume I messed up the EGL context, but why does my entire desktop need to crash? Xkill is a much better UX, and that's kinda sad. An Xorg app failing dramatically doesn't murder my desktop session
- ulrikrasmussen 2y agoAs a user I also just don't care because X11 satisfies all my needs, and I have never really understood why we needed to change the stack.
- bekantan 2y agoStill on XMonad, what are some good alternatives?
- 2y ago
- TypingOutBugs 2y agoI worked on Cardano which is probably one of the larger Haskell projects (and Agda, which lets you write proofs and compile into Haskell!)
- henrebotha 2y agoMan I really want to learn a good code-driven CAD app sometime. Last time I tried to look at ImplicitCAD the website was down so I just gave up lol CADQuery/build123d is the other big one I'm interested in.
- simonmic 2y agoThat got fixed the other day. https://implicitcad.org https://implicitcad.org
- cropcirclbureau 2y agoPostgREST and Hasura (before rewrite) are written in Haskell.
- hiAndrewQuinn 2y agoEveryone else is responding with FOSS, so I'll respond with some companies: Co-Star, the astrology SaaS, is apparently written with a Haskell backend. I'd love to have seen the casting call for that. I believe the Mercury bank also runs most of their backend stuff on Haskell. Functional languages in general are surprisingly common among financial investment firms. Some of Target's stuff is written in Haskell. I think there was at least one big Facebook project that was written in Haskell, but they may have moved away from it by now. Awake Security does some Haskell stuff. One thing which might be surprising is Haskell is apparently quite strong for general backend web dev.
- internet_points 2y agoI maintain Haskell code for five different customers, some large projects, some smaller, projects of varying ages up to over a decade. All the projects do "server backend" stuff, some web frontend too. I love how secure I feel making changes to things I haven't touched in a while.
- _jackdk_ 2y ago> Haskell is apparently quite strong for general backend web dev Yep. Mostly because of the https://www.servant.dev/ https://www.servant.dev/ framework (but see also IHP, Yesod, and other frameworks). Servant lets you declare your HTTP API at the type level, and then it will infer the correct types for your endpoint handlers. You can also extract OpenAPI specs from it, generate clients for Haskell or other languages, etc. My current employer, Bellroy, uses Haskell for pretty much all new code and Servant for all new HTTP APIs. https://exploring-better-ways.bellroy.com/our-technology-stack-and-how-we-got-here.html https://exploring-better-ways.bellroy.com/our-technology-sta... is an older post discussing the shift to Haskell. We've found Haskell code to be much more compact than the equivalent Ruby, and significantly more robust.
- hiAndrewQuinn 2y agoGoing from Ruby to Haskell is, itself, quite a good signal of quality for me. Start strong and end stronger. Sounds like you've got a good thing going!
- epolanski 2y agoI like Haskell, but I think it suffers from the same issues preventing most lisps to gain any traction: every codebase is different and reinvents its own DSL or uses different extensions. Lispers hailing macros and metaprogramming cannot understand that power is also the very thing that makes jumping from project to project difficult, I have no intention of relearning your cleverly designed DSL or new extensions. There's a reason why Java or PHP have plenty of widely used killer software, while monocle-wielding lispers and haskellers have very little to show after many decades. It's not FP being the issue, it's just that their power attracts crowds interested in code more than the features/business/product. I don't blame them, I love Haskell and Racket but I think very few teams can scale and make the compromise worth it.
- kreetx 2y agoThe upside for haskell is that whenever you come to some new code, or return to your own old DSL-y code, the types are there as spikes in a cliff to help you move onward. With, e.g elisp, I always get a mild headache when I need to add some new feature to a codebase I myself wrote.
- colordrops 2y agoPerl was like this, though it did have wide adoption at one point. But people got sick of having 20 ways to do the same thing so Python was born. Is there an equivalent in the FP world?
- internet_points 2y agohttps://tidalcycles.org/ https://tidalcycles.org/ – think ImplicitCAD but for live music performances? also http://detexify.kirelabs.org/classify.html http://detexify.kirelabs.org/classify.html was surprisingly useful in university
- endgame 2y agoThe other ones most people point to are https://pandoc.org https://pandoc.org and https://shellcheck.net https://shellcheck.net
- Locutus_ 2y agoI've used Haskell several times for implementing isolated 'maths business logic units in commercial backend applications. In one such system I built had the main (REST API exposing) backend implemented in Kotlin with a separate application in Haskell doing a complex set of maths driven business rules against GIS data to calculate area specific prices. The amount of IO on the Haskell side was fairly minimum and abstracted away quite nicely. Haskell allowed expressing all complexity in a way that was easy to audit and translate from business/data analyst requirements. Would do again :-) But only with the correct amount isolation so you can lean into Haskell's strong sides.
- IshKebab 2y agoI think Pandoc too, but yeah it's a fairly accurate meme that Haskell isn't really used to make anything except Haskell compilers and tutorials. Last time I checked there was actually an exhaustive list of software written in Haskell somewhere, which they meant as a "look how successful it is - all these projects!" but is really "it's so unsuccessful we can actually write down every project using it".
- simonmic 2y agoHere you go :) https://joyful.com/Haskell#What+Haskell+apps+are+out+there+%3F https://joyful.com/Haskell#What+Haskell+apps+are+out+there+%...
- IshKebab 2y agoOh yeah I was thinking of this list: https://wiki.haskell.org/Haskell_in_industry https://wiki.haskell.org/Haskell_in_industry Imagine a "Go in industry" page. Even a "Rust in industry" would be laughable at this point. Ok I'm maybe being a little unfair, but you get the point.
- simonmic 2y agoThat wiki page is very old. But yes, some such list is still needed for now, because people keep wondering about it.
- cryptonector 2y agoYou're missing out if you don't know about PostgREST.
- deleted 2y ago[deleted]
- imoverclocked 2y ago> and (c) requires a language feature (sequence points) to disambiguate in which order side effects get executed. With Haskell, we just don’t have to care. Reading up to this point, I had to chuckle a bit. I have struggled with the Haskell type system more than I care to admit; It's almost never "we just don't have to care" when comparing to most other popular languages. That being said, this article does a nice job of gently introducing some of the basics that will trip up somebody who is casually looking through code wondering what *> and <*> and <* do. As usual, there is a steep learning curve because of stuff like this all over the codebase. If I walk away for a month, I need to revisit >>= vs >> and other common operators before I can be productive. It probably doesn't help that I never actually speak to a human about these concepts so in my head it's always ">>=" and not "bind."
- internet_points 2y agoI try to avoid >>= and >> (or *>) because I know it trips people up; do-notation is more than fine. The exception is when parsing with one of the parsecs where you get a lot of <* and *> usage and all the tutorials use those symbols. But I like <|> , it feels very clear that it has a sort of "or" meaning.
- youerbt 2y agoOne exception for me about >>=, is instead of this: thing <- getThing case thing of writing this: getThing >>= \case Not so much because it is less code, but fewer variables to name.
- deleted 2y ago[deleted]
- haskman 2y agoI gave a talk that goes more into what makes imperative programming better with Haskell compared to traditional imperative languages. https://speakerdeck.com/ajnsit/supercharged-imperative-programming-with-haskell-and-fp https://speakerdeck.com/ajnsit/supercharged-imperative-progr... In a nutshell, first class effects and built in set of patterns for composing them get rid of boilerplate code. Combine that with type safety and you can churn out relatively bug free code very fast.
- amelius 2y agoWhen will we get the best of both worlds where the imperative parts of a Haskell program run at C++/Rust speeds?
- dismalaf 2y agoProbably never since Haskell is always copying and GC'ing data...
- amelius 2y agoWell, you could implement (in Haskell) a separate heap for (all or some of the) imperative code.
- lmm 2y agoWe've had Scala for about 20 years. (Is the JVM quite C++/Rust speed? No. But it's close enough for any realistic use case)
- deleted 2y ago[deleted]
- zwnow 2y agoWith the downside of 99% of all devs not understanding anything. Sure haskell may be a great language, but even greater languages are accessible.
- mbwgh 2y ago> >> is an old name for > I once had a hard to track down bug in some code making use of conduit[0], which is introduced using examples like `main = runConduit $ (yield 1 >> yield 2) .| mapM_C print`. Dutifully replacing every occurrence of (>>) with (>), because it was more modern, suddenly changed the semantics somewhere, due to the fact that (>>) is defined with fixity `infixl 1 >>` and (>) as `infixl 4 >` - i.e. both are left-associated operators, but (*>) binds tighter than (>>) and some of the myriad of other operators you may encounter. -- [0] - https://github.com/snoyberg/conduit https://github.com/snoyberg/conduit
- _0ffh 2y agoMaybe I'm not so bad for using "superfluous" braces quite often, although this is not specifically the reason why I do.
- tome 2y agoThis is a bit surprising. Why replace `>>` with `*>` "because it's more modern"? Can't you just stick with what's working? The former hasn't been deprecated.
- mbwgh 2y agoYou are absolutely correct and I was an idiot without a proper understanding of premature abstraction or unnecessary complexity. If I were to start a new side-project using Haskell today (I probably won't), I would just stick to do-notation and even concrete types (instead of mtl-style or what have you) where possible.
- sfvisser 2y agoThe generalized version of ‘traverse/mapM’ that doesn’t just work for lists, but any ‘Traversable’ type is absolutely amazing and is useful in so many cases. ‘traverse :: Applicative f => (a -> f b) -> t a -> f (t b)’ And you can derive it for free for your own datatypes! The amount of code I’ve manually written in other languages to get a similar effect is painfully large.
- tromp 2y agoThe fully qualified type is traverse :: (Traversable t, Applicative f) => (a -> f b) -> t a -> f (t b) and deriving it for your own types is as simple as data MyType ... = ... deriving (Traversable)
- sfvisser 2y agoCorrect! I simply copied the definition from the type class, but the context is important.
- rrgok 2y agoCan you kindly make a real word example that is not usual Maybe or Either example, that uses user defined data type? I understand how Applicative works, but I don’t know how to apply (pun intended) to my data types.
- lmm 2y agoI had a generic report class that essentially fetched a bunch of database rows, did some stuff for each row, and then combined the results together into a report. (This was in Scala, I know Haskell doesn't have classes, but presumably similar situations can happen) For one client, we needed to accumulate some extra statistics for each. For another, we needed to call their web API (so async I/O) to get some of the data used in the report. By making the generic superclass use a generic Applicative type, we could keep the report business logic clear and allow the client-specific subclasses to do these client-specific things and have them compose the right way. Wanting custom applicative types is rarer than using a standard one, but it can be a good way to represent any kind of "secondary effect" or "secondary requirement" that your functions might have. E.g. "requires this kind of authorisation" or "must happen in a database transaction". But a lot of the time you can implement custom things using reader/writer/state, or free, rather than having to write a completely from-scratch applicative.
- paulg2222 2y ago[dead]
- BoingBoomTschak 2y agoAm I the only one who never tried Haskell but who when reading discussion about it ends up thinking real-world (with GHC extensions) Haskell has way too much (sometimes historical) cruft? It really detracts me from it.
- kreetx 2y agoWhat cruft?
- tasuki 2y agoThe standard library is atrocious, mainly I believe for historical reasons: - map only works on Lists (one needs fmap for functors) - head throwing exceptions instead of returning Maybe - dependent types bolted on later: they're much nicer in Idris
- kreetx 2y ago- map is easier on newcomers. Once you you understand functor, you'll remember to use fmap anyway. Also, I still use map for lists after 10+ years. - I don't fully understand this, but do you mean that every `IO a` function would be better off being `IO (Maybe a)`? - AFAIK, there are no dependent types in Haskell yet, but say that the type level programming you can do today is what you mean then you are already in quite advanced territory. Yeah, I guess it could be more polished.
- tasuki 2y agoI mean that `head` should be `List a -> Maybe a` rather than `List a -> a`. If you really really want an `a`, you should provide `NonEmptyList a` or something.
- tromp 2y agoHaskell provides https://hackage.haskell.org/package/base-4.21.0.0/docs/Data-List-NonEmpty.html https://hackage.haskell.org/package/base-4.21.0.0/docs/Data-...
- lincpa 2y ago[dead]
- 708145_ 2y agoIt is definitely not procedural. "This seems rather … procedural. Even though we get all the nice guarantees of working with side effectful functions in Haskell, the code itself reads like any other procedural language would. With Haskell, we get the best of both worlds." Working with the IO monad is much more complex, especially if you want to use other monadic types inside that code.
- tome 2y ago> Working with the IO monad is much more complex, especially if you want to use other monadic types inside that code. Yes, mixing other monadic types with IO can be a challenge. One possible solution to that is not just not use other monadic types inside the code. Just use a general-purpose effect system instead. I recommend effectful or Bluefin (the latter my own project).
- scotty79 2y agoIt's a very good explanation but I'd welcome more humility. Instead of using phrase lie-to-kids, I could say that all the dance around effects in Haskell is just implementation detail and/or leaky abstraction.
- ay 2y agoHaskell dilettante here… The “IO a” vs “a” reminded me of async vs sync - where the first one returns a promise/future to be awaited on, rather than a result. Is there any parallel there, or is it an entirely wrong perception I got ?
- moffers 2y agoThere’s a parallel because Promises in a language like JavaScript are “monad-like”, so they’re similar to the IO Monad here. I am not a functional wizard so I’m sure that was not a fair comparison in some way, but it’s how I have thought of it. They’re both a representation of a side effect and require that effect be respected before you can get to the value inside it
- svieira 2y agoNot so much a representation of a side effect (after all List is a Monad as is addition on integers no side effects anywhere in sight) as the reification of a particular category. JavaScript's `Promise` is particularly interesting because it is a Monad over "all JS values which do not contain a method called `then` in their prototype chain" or as Dominic put it 12 years ago: > Indeed, I like the way @medikoo phrases it. There's, practically speaking, nothing wrong with being a monad on the category of non-thenables. https://github.com/promises-aplus/promises-spec/issues/101#issuecomment-16665586 https://github.com/promises-aplus/promises-spec/issues/101#i...
- acjohnson55 2y agoYes, except in a lot of languages, a Promise is the representation of the result of a computation that may already be happening, whereas an IO is a computation that will have data injected into it by some interpreter. But it's a very close comparison, in the sense that both represent contexts that future computation can be appended on. Also, in some languages, the Promise type is truly monadic.
- lucasoshiro 2y ago> Is there any parallel there Of course. Promise is a monad, .then is more or less equivalent to the >>= operator and await makes it look more imperative-ish just like <- in Haskell. Note that in JS you'll need to be inside an async function to use await, just like in Haskell you'll need to be inside the do notation to use <-. Otherwise, you'll need to play with .then just like you would need to play with >>= in Haskell. About other languages, one way to achieve asynchronous behavior without having it implemented in the language is using ReactiveX (https://reactivex.io/ https://reactivex.io/). It's hard to understand at first, but it if you understand the IO Monad it becomes easy, as it's basically the same.
- deleted 2y ago[deleted]
- hackandthink 2y agoHaskell has strong monads, missed this in the article. It makes Haskell even more procedural, you can use intermediate variables in do blocks. http://blog.sigfpe.com/2023/08/what-does-it-mean-for-monad-to-be-strong.html http://blog.sigfpe.com/2023/08/what-does-it-mean-for-monad-t...
- fire_lake 2y agoIn other languages we can do a poor man’s IO with a function like: () => console.log(“abc”) Is this really so different from IO everywhere in Haskell?
- mrkeen 2y agoWhen you express it has "Haskell has the IO monad" and "Haskell has the Maybe monad", it's no biggie because other languages have them. All Java Objects might or might not be there (so they all implement Maybe). And all Java methods might or might not do IO, so they all implement IO. The real sell is: Haskell objects which are not Maybe are definitely there. Functions which are not IO will always give the same input for the same output.
- corank 2y agoI think as long as the code sticks to the discipline of never actually doing I/O but only manipulating functions that perform them it would basically be doing the same thing as IO monads in Haskell. So print(s) returns a function that when called prints s. Then there needs to be function that joins those functions, so print(a); print(b) evaluates to a function that once called prints out a and then b. What makes Haskell special in my opinion is 1) it generalises this way of achieving "stateful" functions, 2) enforces such discipline for you and makes sure calling functions never produces side effects, and 3) some syntactic sugar (do, <-, etc) to make it easier to write this kind of code. Also note that the above example only does output which would be the easier case. When it comes to code with input, there will suddenly be values which are unavailable until some side effects have been made, so the returned functions will also need to encode how those values are to be obtained and used, which complicates things further.
- deleted 2y ago[deleted]
- lucasoshiro 2y ago> Is this really so different from IO everywhere in Haskell? It's a starting point. You'll have to somehow chain (e.g. you want to print "def" after "abc", how would you do that?). You'll also need to put a value into your IO, e.g. if you are inside that IO, all the computations will need to produce IO. If you solve those things, you'll have a Monad. But, wait! You're in JS, right? You have IO Monads there, perhaps only don't know yet. They are the JS Promises! Look this: // assuming that you have a sync input function, that receives a string from stdin and returns it let input_str = new Promise((resolve, reject) => resolve(input()); let input_int = input_str.then(s => parseInt(s)); let square = input_int.then(n => n * n); square.then(sq => console.log(sq)); If you want to proceed with your poor man's IO, you'll need to implement your "then". Going further, the equivalent in Haskell (not the best code, though) to that is: main = result where input_str = getLine input_int = input_str >>= \s -> return (read s) :: IO Int square = input_int >>= \n -> return (n * n) result = square >>= \sq -> putStrLn (show sq) Ok, but Haskell has a syntax for cleaning that, called do notation: main = do input_str <- getLine let input_int = read input_str :: Int let square = input_int * input_int putStrLn (show square) And JS? JS has also its syntax, using await. Just like Haskell that it only works inside the do notation, in JS it will only work inside async functions: let input_str = await new Promise((resolve, reject) => resolve(input())); let input_int = parseInt(input_str); let square = input_int * input_int; console.log(square);
- mppm 2y agoThe way I think about effectful computation and IO in Haskell is as a kind of enforced metaprogramming. The actual language comprises a strongly typed meta-layer used to assemble an imperative program from opaque primitives. Like all powerful metaprogramming systems, this allows doing things you cannot easily do in a first-order imperative language. On the other hand, this makes all the 99% of simple stuff you don't have to even think about in an imperative language necessarily roundabout, and imposes a steep learning curve. Which contributes to the empirical fact that not many people are rushing to use Haskell, the superior imperative language, in real-world projects.
- tome 2y ago> The way I think about effectful computation and IO in Haskell is as a kind of enforced metaprogramming If you think of effectful computation in Haskell to be a sort of metaprogramming, then indeed it will seem very complex, absurdly complex actually. If you think of it as just the same as programming in any other language, except functions that do effects are tagged with a type that indicates that, then I think things will appear much simpler. I prefer thinking of it as the latter, and it's been very effective (pun half intended) for me.