Live data from Hacker News

A couple million lines of Haskell: Production engineering at Mercury

blog.haskell.org

141–150 of 249 posts

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

#141
It's a double-edged sword. Two million lines is a major feat. It's also represents a significant maintenance burden.

The advantages to Haskell are theoretically obvious. The downsides are harder to intuit.

The temptation is to model _everything_ as types. The codebase itseld becomes a _business specification_, not an application. Every policy change is a major refactor (some of which are shockingly high-touch thanks to Haskell safety).

The lesson is you cannot have your cake and eat it too. Eventually you become trapped by your types.

Haskell is really impressive and powerful, perhaps especially at this scale. However it brings its own unique problems. The temptation to model business logic as types leads to rigid structures. And the safety these structures bring can blind you to other classes of risk.

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

#142
post #55
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…

> works really well in Rust and TypeScript too And of course Rust and TypeScript were heavily influenced by Haskell... they just don't mention it and call things differently, to avoid the "monads are scary, I need to write a tutorial" effect. Though it's less about monads and more about things like type classes. Imitation is the sincerest form of flattery.

Rust's influence was OCaml, not Haskell. Its first compiler was written in OCaml. Its syntax directly looks like OCaml and C++ had a baby. It's got ML smells all over it. Haskell is not the sum of Hindley Milner-esque languages.

Personally, never enjoyed Haskell's syntax (or lack of it) and tendency to overthinking. But I did enjoy SML/NJ and OCaml to some extent.

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

#143
post #92

Earlier quoted context omitted.

That "and so on" is doing a lot of work. You may accept rejecting garbage collection as a reasonable trade-off, but the bulk of the cost is coming from a much more aggressive tradeoff Rust is making with is at odds with the goals of most application code. A deeply-baked assumption of Rust is that your memory layout is static. Dynamic memory layout is perfectly compatible with manual memory management, but Rust does n…

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 I can throw an exception and get done with it instead of refactoring all the stack up for the intermediate return types (though I use expected and optional and like them, but it is a choice depending on what I am doing).

I am not going to elaborate safe interfaces for my arrays of data I need to send to a GPU: there is no vslue in it and I can get it wrong snyway, it os ceremony. I assume this kind of code is unsafe by nature.

I find C++ just more flexible. Yes, it has warts, but I use all warnings as errors, clang tidy and have a lot of flexibility. I use values to avoid any trace of dangling and when it is going to get bad, I can, most of the time, switch to smart pointers.

I really do not get why someone would use Rust except for very niche cases like absolutely no memory unsafety (but this is not free either, as some reports show: you need to really be careful about reviewing unsafe if your domain is unsafe by nature or uses bindings to keep Rust invariants or you write only safe code, in whcih case, if memory safety is critical, it does give you something).

But I do not see Rust good for writing general application code. At least not compared to well-written C++ nowadays.

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

#144
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…

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…

> This isn't specific to Rust or Typescript. You can do this in basically any language.

This just isn't true.

In any dynamic language you would not get these guarantees at compile time. You'd get random failures at runtime. That's not safety of any kind.

Also, part of the goal of languages like Haskell is that they help you think about your code before it runs. All of that is lost.

> Imagine you have to distinguish between unescaped and escaped strings for security purposes

That would be a nightmare in many languages. You'd have to rewrite large parts of the code to be compatible with one or both. And in many languages you'd have to duplicate your code entirely.

In other languages, the result would so ugly, you would never want to touch that code. Imagine doing this with say, templates in C++.

>There's a performance cost to this

There is no performance cost in Haskell! This is entirely undone by the compiler.

Also, because the compiler understands what's going on at a much higher level, you can do things like deriving code. You can say that your classified strings behave like your regular strings in most contexts, like say, they're the same for the purpose of printing but not for the purpose of equality, in one line.

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

#146

It's a double-edged sword. Two million lines is a major feat. It's also represents a significant maintenance burden. The advantages to Haskell are theoretically obvious. The downsides are harder to intuit. The temptation is to model _everything_ as types. The codebase itseld becomes a _business specification_, not an application. Every policy change is a major refactor (some of which are shockingly high-touch thanks…

Typescript too: https://www.richard-towers.com/2023/03/11/typescripting-the-...

Tbvh the biggest downside of a Turing complete type system is that you can theoretically implement an application that compiles to dust.

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

#148
post #55

Earlier quoted context omitted.

> works really well in Rust and TypeScript too And of course Rust and TypeScript were heavily influenced by Haskell... they just don't mention it and call things differently, to avoid the "monads are scary, I need to write a tutorial" effect. Though it's less about monads and more about things like type classes. Imitation is the sincerest form of flattery.

Rust's influence was OCaml, not Haskell. Its first compiler was written in OCaml. Its syntax directly looks like OCaml and C++ had a baby. It's got ML smells all over it. Haskell is not the sum of Hindley Milner-esque languages. Personally, never enjoyed Haskell's syntax (or lack of it) and tendency to overthinking. But I did enjoy SML/NJ and OCaml to some extent.

[deleted]

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

#149

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…

“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++.

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

#150
post #116

Earlier quoted context omitted.

You can't enforce purity on the type level in TypeScript and IIRC neither in Rust.

You can't in Haskell either! For example, any function could secretly call `unsafePerformIO` to cause a side effect (and that's not the only example). I believe `const` functions in Rust are actually be guaranteed to be pure, though I haven't followed that feature closely and there may be nuances. In most languages purity is a norm rather than enforced by static analysis. I definitely agree that it's much safer to as…

You can compile Haskell code with the -XSafe flag, and this is communicated in the package, so something like backpack can be told to load only safe modules. Still, there's probably plenty of code that's safe but not pure, but that's as good as we're likely to get.
Post reply on HN