Live data from Hacker News

A couple million lines of Haskell: Production engineering at Mercury

blog.haskell.org

191–200 of 249 posts

Re: A couple million lines of Haskell: Production engineering at Mercury

#191
post #81
post #63

Earlier quoted context omitted.

Pretty surprising -- I had much the opposite experience. On our last product, we decided to start switching from Typescript to Rust on the backend because we got tired of crashes. I consider that to be one of the greatest technical mistakes I've made ever, as our productivity slowed massively. I'll just share two time-draining issues that only occur in Rust: (1) Writing higher-order functions (e.g.: a function to ope…

That's pretty interesting. I was thinking about starting a new pet project and was considering doing it in Rust to learn as I never tried anything with it and after some small pocs I had the feeling it was too verbose to my taste, but wasn't sure it was just me and/or my lack of experience with Rust. Still, wonder if it's still worth it to give a shot considering other positive elements of the language.

Some say verbose, some say explicit. I had the complete opposite reaction to Rust than this other person, and I don’t think I’m particularly smart so I don’t think it’s purely a matter of intelligence. Even asynchronous rust is pretty easy once you get the hang of it.

Re: A couple million lines of Haskell: Production engineering at Mercury

#192

Earlier quoted context omitted.

“I’m not going to use Rust because I don’t like it” seems like what you’re saying, which is totally fine. Plenty of people, myself included, manage to write and enjoy writing general application code in Rust. You’re allowed to not get it, just like I’m allowed to dislike writing C++.

No. That is not what I am saying. I am saying there are contexts where you do not get value out of it and you can potentially decrease your productivity because it is more rigid. You have examples above if you want to read through. In no way I am saying it is useless. I just see niche uses for it compared to alternatives.

No, there are contexts where you do not get value out of it. Don’t speak for others.

Re: A couple million lines of Haskell: Production engineering at Mercury

#193
post #72

Earlier quoted context omitted.

That is a very unusual Rust experience. I find "application code" very pleasant to write in Rust. Of course there are things that aren't as ergonomic in Rust as in other languages (e.g. callbacks) but that's true of pretty much any language.

I have heard this reaction from others before. One of the Rust expert friends I consulted with told me "I'm not convinced you're not trying to write Haskell-style code in Rust;" I told him the patterns I was struggling with were both trivial and common in Java. The things I found quite difficult or impossible in Rust were to me pretty basic patterns for modularity and removing duplication that it's really shocking th…

> Rust afficionados are some combination of people who came to Rust early and never learned traditional software design and don't know what they're missing, and people who were raised on traditional good software engineering but then got hit with Rust's metaphorical baseball bat of lack-of-modularity over and over until they got used to being hit with a baseball bat as a normal pain of life.

Oh please. I came to Rust late, after using plenty of other languages. I have never had a problem with “modularity”. You express surprise that these issues haven’t been talked about more, well the null hypothesis is that you are just not very good at Rust and it hasn’t clicked for you - that’s fine, I doubt I would be very good at Haskell. But don’t insult us, and don’t assume your experience is de facto everyone’s and we’re just in denial. It’s incredibly arrogant.

Re: A couple million lines of Haskell: Production engineering at Mercury

#194
post #157

The problem I have with functional programming is debugging. Or more precisely, I would say it is a strength of imperative programming, especially the procedural kind. In functional/declarative style, you generally describe how things should be, not how things are made, and you let the language piece everything together to get the expected result in the end. It is all well and good (and even better) if you did everyt…

Functional Programming debugging is often "REPL-guided" in a way that imperative programming often is not. This is not unique to functional programming, though. Even the (mostly) imperative languages Python and Javascript you may be more likely to use REPLs of one sort or another (Python shells, browser consoles, Node/Deno/Bun shells, notebooks, etc.) as your first layer of debugging.

There are interesting trade-offs in REPL-oriented debugging. One of the big things is that in a language like C you might often start first from whole program debugging and breakpoints to try to hit exactly where you think the problem is. In a REPL-oriented world you often try to build the components of your program in a way that you can test more units of it directly in the REPL.

Your module/API/Type boundaries in a REPL world become to mirror your debuggability story. There is sometimes more pressure to get those right and easy to use than in imperative languages like C/C++ because you might want to reach for them directly in a REPL.

But yes, a tradeoff versus whole program-first debugging is sometimes it becomes harder to isolate complex integration issues between your units in strange real world scenarios. However, that REPL-first approach is often encouraging of minimizing your integration "surface" to a bare minimum so often FP languages don't exhibit some of the same integration effects you see in imperative languages.

> Harder to do when the language goes out of its way to hide the state from you, as it is the case for functional programming.

Functional programming languages aren't really hiding any state from you. They also are running on imperative hardware and still dealing with real hardware states. At some point there is a translation between the "worlds" (which also likely aren't as different as you seem to think that they are). You still have those imperative breakpoints and imperative debuggers to fallback on.

That's why the term is "REPL-guided" debugging. You can use a REPL to pinpoint the problematic unit (the exact module/API/function) and the problematic input giving you the surprise output. If you can't see the bug in the source as written you can still send it to an imperative debugger and watch nearly the same "line-by-line" experience and hope it provides additional missing context. Even better by that point you probably don't need to choose good "breakpoints" because you've already isolated the problem enough in the REPL to have "natural breakpoints" because the unit you are debugging may be small and narrow enough that stepping just that unit is all you need.

> It is interesting that the longest section of the article is about this problem: "design for introspection", where the author has to go out of his way to make his code debuggable.

I think you found the wrong message from that section. That section wasn't about debuggability it was about observability. It was about connecting logging/telemetry systems correctly, mocking fakes during testing, adding retries/circuit-breakers at a systematic/app-wide level rather than relying on individual libraries to get it right. In the imperative world these aren't debugging issues either: These are Dependency Injection issues. These are Middleware installing issues. These are factoring concerns like using Abstract Interfaces over Concrete Classes at your public API boundary.

The design suggestions are factorings. They don't impact debuggability, they impact how easy it is to install observability middleware to someone else's public API.

Re: A couple million lines of Haskell: Production engineering at Mercury

#195
IMO types are the main lever you can use other than procedural abstraction. I feel that Haskell gives you both in a way that marries them for maximum constraint-building. Constraints that prevent illogical or illegal programs are the bread and butter of reliable software.

Re: A couple million lines of Haskell: Production engineering at Mercury

#196
post #100

Earlier quoted context omitted.

This isn't specific to Rust or Typescript. You can do this in basically any language. Imagine you have to distinguish between unescaped and escaped strings for security purposes. Even with a dynamically typed language, you can keep escaped strings as an Escaped class, with escape(str)->Escaped and dangerouslyAssumeEscaped(str)->Escaped functions (or static methods). There's a performance cost to this, so that's a tra…

What you cannot do is compile-time safety guarantees, and in languages like Rust type system isn't strong enough to do some advanced compile-time guarantees (via types). So no, you cannot do this in basically any language (unless you turn it into Haskell).

Can you give some examples? What is Haskell’s type system capable of that you can’t express in rust?

Re: A couple million lines of Haskell: Production engineering at Mercury

#197
post #63

Earlier quoted context omitted.

Pretty surprising -- I had much the opposite experience. On our last product, we decided to start switching from Typescript to Rust on the backend because we got tired of crashes. I consider that to be one of the greatest technical mistakes I've made ever, as our productivity slowed massively. I'll just share two time-draining issues that only occur in Rust: (1) Writing higher-order functions (e.g.: a function to ope…

I'm not a Rust expert by any means, but I'm surprised to hear this. In my Rust code, doing anything with a database connection is not at all different from, say, Go or TypeScript. For example, I use the deadpool-postgres crate for database pooling. Getting a connection looks like this: let conn = self.pool.get().await?; Because of RAII, you don't need a higher-order function helper, but if you really wanted to make o…

Just investigated -- looks like this works now! Yay!

For this family of examples, had been completely stymied by AsyncFnOnce not being released yet. IIRC it had been in the works for several years, was still an experimental feature when I was trying to use it, and I gave up after much frustration at trying to get a version of Rust with experimental features working under devenv (nix).

A subtraction then to my frustrations with Rust -- though I'd still be very wary of doing this, having seen how fragile higher-order functions have been in the past.

Re: A couple million lines of Haskell: Production engineering at Mercury

#198
post #106

Earlier quoted context omitted.

What the parents describe can be done with almost any language.

No you cannot

They described the use of abstract data types. One can certainly use those in most languages - for sure in C.

Re: A couple million lines of Haskell: Production engineering at Mercury

#199
post #33

risky move, what is the talent pool for Haskell devs these days?

The article has a section covering this. According to them, finding Haskell talent is not difficult, the bigger problem is onboarding them into the company coding style because Haskell developers come with strong opinions.

Re: A couple million lines of Haskell: Production engineering at Mercury

#200

Earlier quoted context omitted.

I badly want to try out Mercury, in fact I have an account already, but they don't yet support Zelle. I really hope their national bank charter application gets approved. (They applied for one last December.) Once they support Zelle, I'll drop U.S. Bank, as their app sucks and they don't have an API.

https://www.businesswire.com/news/home/20260427949683/en/Mer... .

Awesome!!
Post reply on HN