Live data from Hacker News

A couple million lines of Haskell: Production engineering at Mercury

blog.haskell.org

171–180 of 249 posts

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

#171
post #57
post #34

Earlier quoted context omitted.

> You can do this in basically any language. You can do it in Assembly. That doesn't mean it's cost effective.

Costs are a skill issue ;-)

You demonstrate well the problem: yes anything that is computable can be than in any computation system. That's not what discussions about tooling are about.

If a tool can help enforce some ways of doing things, or if it doesn't constrain people much, that has consequences for the type of work that gets done with them and the systems you encounter running out there that you might be invited or find the need to work with.

"I can do it" is exactly the wrong answer. "How can I guarantee that others will do it" is the point being made.

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

#172
post #6

It’s hard to imagine what two millions lines of Haskell could possibly be doing. I mean that’s a lot of code and I have the impression that Haskell is “tight” meaning a little code can do a lot. Maybe they have a lot of libraries to do things like json serializing/deserializing, rest api frameworks, logging etc?

Nit: the quality of a language that you call "tight" is usually called "expressive." You can use few characters to express a relatively very abstract idea. Some people call this "high-level," too. I will say, though, that 2 million lines of code is much less code than it sounds like at first glance, especially for a company in a highly-regulated space like finance, plus a few years of progress.

Agree on the 2M lines of code point. Looking at GitHub stats, I’ve personally written about 500k loc over the last 6 years, and that’s not including my teammates contributions etc. There are a lot o f things on our roadmap and I would consider the codebase to still be immature a feature incomplete. And this is all for a particular niche in a gigacorp.

If anything, having your entire company’s codebase be 2M loc and it be a functional product seems reasonably efficient to me.

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

#173
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.

Verbosity aside, whether or not Rust is a good fit depends on what you are doing. The language design is broadly optimized for low-level application code, like command-line utilities. If that is the use case then you are likely to have a good experience.

For high-performance and high-reliability systems code, Rust is much more of a mixed bag. In a systems context it lacks the ability to easily and ergonomically express idiomatic constructs important for safety and performance that are trivial to express in e.g. C++. When you run into these cases it can get pretty ugly.

Most people don't write this kind of systems code. What most people call "systems code" is really more like low-level applications code, where Rust excels. It is software like highly-optimized kernel-bypass database engines and similar where the limitations start to show.

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

#174

Earlier quoted context omitted.

I'm not convinced it really works well in typescript. the lack of nominal types requires you to remember some pretty hacky incantations if you want something like a newtype wrapping a primitive type my experience is that ocaml is more powerful than rust for enforcing this sort of type safety, because you have gadts that give you more expressive power, and polymorphic variants and object types (record row types) that…

It really feels like we’re solving the wrong problem sometimes. If a bad type can crash your application, sure, type safety is one answer but I have to admit I like the erlang approach; if something unexpected happens crash the process (not os process, erlang process) which has a very small blast radius on a well architected system (maybe doesn’t even fail the individual request that caused it). I wish more languages…

Or have a static type system and something like BEAM. I'm not sure why this is a one or other approach, both are useful and unfortunately it doesn't seem like any languages include both. Gleam exists but doesn't really integrate with BEAM, it seems to have its own way of doing things that are more akin to Haskell, given its origins.

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

#175
post #7

> Haskell gives you tools to encode these incantations in types so they cannot be forgotten. This is, for my money, the single most valuable thing the language offers a production engineering organization. Haskell is admittedly, probably the most powerful widely (or even somewhat widely) used language for doing this, but this general pattern works really well in Rust and TypeScript too and is one of my very favorite…

"Make invalid states unrepresentable," as I have posted here before: https://news.ycombinator.com/item?id=40150159

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

#176
post #114
post #7

> Haskell gives you tools to encode these incantations in types so they cannot be forgotten. This is, for my money, the single most valuable thing the language offers a production engineering organization. Haskell is admittedly, probably the most powerful widely (or even somewhat widely) used language for doing this, but this general pattern works really well in Rust and TypeScript too and is one of my very favorite…

“Parse don’t validate“ seems like the same idea https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-va... You do not need Haskell for that eg it works in Python (via pydantic, attrs data classes)

It's more similar to "Make invalid states unrepresentable": https://news.ycombinator.com/item?id=40150159

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

#177

My bestie works at this company and looking from the outside they have a good engineering culture. I do think Haskell is the right tool for the job, and they are playing to it's strengths, but part of me wonders if a lot of their success is attributable to the place just being well run in general.

That would not run counter to the popular (whether true or not) idea that by using functional programming languages you filter for a higher quality labor pool / applicant pool.

That wouldn't apply here, since as the article says they hire "generalists, and most of them have never written a line of Haskell before joining."

In any case, I think the "Haskell tax" concept (where you can pay well-paid programmers less if you have a Haskell shop) is stale by now. Rust attracted away a lot of FP-ers, plus mainstream langs like C++, Java and even Typescript got smarter. Haskell's biggest problem by far is the tiny labor pool, which Mercury seems to wisely avoid.

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

#178

Earlier quoted context omitted.

You can usually manage dyn compatibility issues in my experience by writing a base trait that is not dyn compatible and then an Ext trait that is, which is auto implemented for all implementers of the base trait. You see this pattern all over the place, including with several of the buffer traits you mentioned. Mostly, this works out well enough: dyn compatibility pretty much just insists your methods can in fact wor…

Some people ask me why I do not use Rust as opposed to C++ if it is already safer and more modern. But I see the forums (and I also trued some toy stuff at times) plagued with rigidity problems that in C++ have obvious solutions. For example, I am not going to fight a borrow-checker all the stack up to get a 0.0005% perf improvement, if sny, when I can use smart pointers. I am not going to use Result everywhere when…

[deleted]

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

#179

Earlier quoted context omitted.

It really feels like we’re solving the wrong problem sometimes. If a bad type can crash your application, sure, type safety is one answer but I have to admit I like the erlang approach; if something unexpected happens crash the process (not os process, erlang process) which has a very small blast radius on a well architected system (maybe doesn’t even fail the individual request that caused it). I wish more languages…

Or have a static type system and something like BEAM. I'm not sure why this is a one or other approach, both are useful and unfortunately it doesn't seem like any languages include both. Gleam exists but doesn't really integrate with BEAM, it seems to have its own way of doing things that are more akin to Haskell, given its origins.

I thought gleam was fully integrated with otp? You’re telling me you can’t do a gen_server or a supervisor in gleam?

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

#180
post #63
post #47

I loved working in Haskell for a few years. I wasn't actively looking it, but the opportunity just sort of landed in my lap. It was exciting and mentally stimulating. But the unfortunate fact is, I am easily twice as productive in Rust as I am Haskell, even after 3 years of nothing but Haskell. There are more pitfalls in Haskell that you have to just know how to avoid. It can be very difficult to digest as the langua…

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 one:

    async fn with_conn(
        &self,
        f: impl AsyncFnOnce(Object) -> Result,
    ) -> Result {
        let conn = self.pool.get().await?;
        f(conn).await
    }
Now you can do:

    with_conn(|conn| async move {
      conn.query("SELECT 1")  // Or whatever
    }).await
If you know TypeScript, this shouldn't be too difficult to read or write. The gnarliest stuff here is knowing the type signature of the function argument; because of async, it must be AsyncFnOnce, for one, and you need to know that the type that the deadpool crate returns is called Object (which doesn't sound like a connection, to be fair). Determining the exact concrete type to match type constraints on is sometimes a chore, but TypeScript is surely no different here!

If you don't know Rust too well, the "move" part will be a little mysterious, to be sure.

Post reply on HN