Live data from Hacker News

A couple million lines of Haskell: Production engineering at Mercury

blog.haskell.org

241–249 of 249 posts

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

#241
post #210

Earlier quoted context omitted.

From TFA: > The problem is that we cannot trust code we cannot instrument. If a third-party binding makes HTTP calls through concrete functions, we have no way to add tracing, no way to inject timeouts tuned to our SLOs, no way to simulate partner outages in testing, and no way to explain the 400ms gap in a trace except by squinting at it and developing theories. So we write our own. More work upfront, but the client…

> If a third-party binding makes HTTP calls through concrete functions, we have no way to add tracing, no way to inject timeouts tuned to our SLOs, no way to simulate partner outages in testing, and no way to explain the 400ms gap in a trace Given that tracing etc. is IO, are they just threading IO through the entirety of all their Haskell code?

Tracing doesn’t actually require IO, only emitting the traces does, and those two need not be done at the same point.

In any case, anywhere they’re doing HTTP calls they are already threading IO, so they don’t have to pay an additional cost.

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

#242
post #100

Earlier quoted context omitted.

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).

Rust (and Scala) type systems are somewhat stronger and more expressive in some areas than Haskell. Weaker in some other. But it’s not a clear cut that Haskell type system offers more safety guarantees.

  > But it’s not a clear cut that Haskell type system offers more safety guarantees.
You can log operands in your implementation of Rust's Add trait, or compute running sum of one of the operands. In Haskell it is not possible unless you use unsafePerformIO from System.IO.Unsafe.

Haskell's type system controls effects available to the code. This can be used to implement programs adhering to specific formulas of Linear Temporal Logic or implementing a protocol specification, where operations on any given phase and side are restricted by type system.

I used Haskell's type system to prevent crossing of clock domains in the hardware description eDSL. Also, it was of great help in the CPU simulator description, fixing available commands and resources for different CPU models.

Even the logic of Rust's borrow checker was expressible in Haskell as early as February 2009 - there was HList, there was ParameterizedMonad and that's about what one needs for implementation of borrow checker.

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

#243

Earlier quoted context omitted.

Without having run the whole company twice in parallel, once using Haskell and again in some other language, and without having measured both runs exactly the same way, I don't think metrics like you're interested in could possibly have sufficient context to mean anything reliable. Obviously Mercury is successful, and obviously Haskell is how they did it. So it's essential to their success. Would it be instrumental t…

I’m asking for solutions and answers. Yeah. I’m aware of how hard it is to get metrics. You can still compare lines of code and bug rate over the same period of time.

You can, but then "The cake is a lie.", because linecount and bug rate, when concieved as proxies for productivity[1] or quality rarely match up with reality in a way that allows you to make predictions or reason about past outcomes.

You can reason about frequency of particular types bugs, such as null pointers or overflow, or whether those bugs can occur at all.

[1] https://www.folklore.org/Negative_2000_Lines_Of_Code.html

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

#244

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…

> There's a performance cost to this That part is (de facto) required for dynamically typed languages, but not for statically typed ones where the newtype constructor/deconstructor can be elided at compile time. Rust and C++ especially both do the latter by having true value types available for wrappers that evaporate into zero extra machine code. But then just this moment I wondered: do any major runtimes using mode…

> [Performance cost] is (de facto) required for dynamically typed languages, but not for statically typed ones where the newtype constructor/deconstructor can be elided at compile time.

For a single value, it should reliably be free in any reasonable statically typed language that meet your other criteria.

For a collection, it may still be de facto required. Unwrapping a set of addresses into a set of strings takes unnecessary cycles, an unsafe coercion, sufficiently sophisticated affordances around coercion that it can be safe, or a smart enough optimiser. At least some static languages have at least one of these; I'm not sure all do, and certainly not all have always had.

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

#245

Earlier quoted context omitted.

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?

It still doesn't have hot reload support which is critical in BEAM. It simply doesn't handle it the same way as Erlang.

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

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

> You can do this in basically any language.

Tell me you haven't understood what a type system does without...

A type system mathematically proves, at compile time, what a program can and cannot do. No, you can't "do this in basically any language".

It's ironic that "shift left" is generally considered a good thing', but when you point out that you can shift a significant majority of checks left all the way to compile time, they say "no, not like that!"

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

#247

Earlier quoted context omitted.

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

It still doesn't have hot reload support which is critical in BEAM. It simply doesn't handle it the same way as Erlang.

I'm running BEAM in production for almost 8 years and not once have I used hot code reloading. Why is that critical?

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

#248

Earlier quoted context omitted.

It still doesn't have hot reload support which is critical in BEAM. It simply doesn't handle it the same way as Erlang.

I'm running BEAM in production for almost 8 years and not once have I used hot code reloading. Why is that critical?

That's literally the entire point of BEAM lol, that's one of the main reasons it was made, to patch code that breaks after letting it fail. BEAM was designed for as little downtime as possible and if you don't need that then just use another more ergonomic language than Erlang or Elixir.

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

#249
post #235
post #232

I wish people'd report metrics like "40 type classes, 5000 functions, 300 instances, 20 monads, 14 functors, ..." And such instead of "lines of haskell".

I wish people'd report metrics like "transactions per second, 99.x% availability with N secs/mins p99 latency, ..." when describing how practically useful and how effective a real-world banking/transaction system is, which further proves the practicality of the programming language.

Those inseparably mix up programming language, compiler, programmer(s) and application domain as factors.
Post reply on HN