After 7 years in production, Scarf has reluctantly moved away from Haskell

After 7 years in production, Scarf has reluctantly moved away from Haskell

在生产环境运行 7 年后,Scarf 遗憾地告别了 Haskell

Avi Press | July 10, 2026 — Disclaimer This has been a hard post to write. I almost didn’t write it at all, since I prefer to build and promote than to critique. However, I hope this post can add constructively to the discussion about Haskell’s future. I must underline that I’m not writing this criticizing Haskell from the outside. I care enough about Haskell to be honest about why Scarf has reluctantly moved away from it, in hopes it sways people in the community to take this feedback seriously.

Avi Press | 2026年7月10日 — 免责声明:写下这篇文章对我来说非常艰难。我差点就放弃了,因为我更倾向于建设和推广,而不是批评。然而,我希望这篇文章能为关于 Haskell 未来的讨论提供建设性的意见。我必须强调,我写这篇文章并非是以局外人的身份批评 Haskell。我足够关心 Haskell,因此才坦诚地说明 Scarf 为何遗憾地放弃了它,希望这能促使社区成员认真对待这些反馈。

Where I’ve been For the last 16 years, I have been a huge fan of Haskell. It has been undeniably the most important programming language in my life. Learning it made me a much better programmer. I have advocated for it, built a company that runs on it, and I serve on the board of the Haskell Foundation and the Haskell.org committee. I have also been open about the places where I think Haskell needs to improve.

我的背景:在过去的 16 年里,我一直是 Haskell 的忠实拥趸。不可否认,它是对我人生影响最重要的编程语言。学习它让我成为了一名更好的程序员。我曾为它摇旗呐喊,创办了一家基于它运行的公司,并且目前在 Haskell 基金会和 Haskell.org 委员会任职。同时,我也一直公开表达过我认为 Haskell 需要改进的地方。

Since Scarf launched, our backend has been built in Haskell. The main API that powers our app uses libraries like Servant, Beam on top of PostgreSQL. We also built a high-performance Haskell service for Scarf Gateway directly on top of WAI, which sits directly in the download path for a high volume of open source package traffic. These systems have real uptime requirements, contractually committed SLAs, and we have managed that successfully in production for years. We put Haskell through a serious production test, and many of its promises held up. The code was reliable. The type system caught real bugs. The language forced us to be thoughtful about how we modelled our domain. High performance code has been generally straight-forward to achieve.

自 Scarf 发布以来,我们的后端一直是用 Haskell 构建的。驱动我们应用的主 API 使用了 Servant 和基于 PostgreSQL 的 Beam 等库。我们还直接在 WAI 之上为 Scarf Gateway 构建了一个高性能的 Haskell 服务,它直接处于大量开源软件包流量的下载路径中。这些系统有着真实的正常运行时间要求和合同承诺的 SLA(服务等级协议),我们已经在生产环境中成功管理了多年。我们对 Haskell 进行了严格的生产测试,它的许多承诺都经受住了考验。代码非常可靠,类型系统捕获了真实的 Bug,这门语言迫使我们在建模领域时进行深入思考。实现高性能代码通常也比较直接。

But the costs were real too. The biggest ones were compilation time and ecosystem friction. We spent a lot of time optimizing builds, caches, Nix, developer environments, CI, and all the other machinery you end up needing around a serious Haskell codebase. For a long time, that was workable. Our team knows the language and tooling deeply. We knew where the sharp edges were, and we mostly lived with it. Then AI changed the tradeoffs.

但代价也是实实在在的。最大的问题在于编译时间和生态系统的摩擦。我们花费了大量时间来优化构建、缓存、Nix、开发环境、CI 以及围绕严肃的 Haskell 代码库所必需的所有其他机制。在很长一段时间里,这是可行的。我们的团队对这门语言和工具链有深入的了解。我们知道哪些地方是“坑”,并且大多时候都能忍受。然后,AI 改变了权衡标准。

Haskell after AI LLMs are now very good at writing code. They are not perfect, obviously, but they are good enough that the economics of software development have changed. Historically, I thought about errors as something you caught in one of two places: at compile time or at runtime. Now there is a third place: code generation time. The model can often avoid the mistake before the compiler ever sees the code. And as the models get better, the relative value of catching every possible issue at compile time changes. This is not to say type safety has become worthless. But the cost of typechecking matters much more now.

AI 时代的 Haskell:大语言模型(LLM)现在非常擅长编写代码。显然它们并不完美,但已经足够好,以至于软件开发的经济性发生了改变。过去,我认为错误是在两个地方捕获的:编译时或运行时。现在有了第三个地方:代码生成时。模型往往能在编译器看到代码之前就避免错误。随着模型变得越来越好,在编译时捕获所有可能问题的相对价值也随之改变。这并不是说类型安全变得毫无价值,但类型检查的成本现在变得更加重要。

If an LLM can produce a working implementation in a few minutes, but your compile step takes dramatically longer, then your language and build system have become a bottleneck in the development loop. The important metric: how long does your entire development feedback cycle take, and what portion of that time is spent waiting on your compiler? If a human spends an hour writing some code, a long compile cycle is annoying but may be tolerable. If an agent can draft a plausible change in minutes and then spends even 15 minutes waiting for the project to build from a cold start, the compiler has now moved from being a papercut to being the dominant cost of that thread of work.

如果 LLM 可以在几分钟内生成一个可用的实现,但你的编译步骤却需要长得多的时间,那么你的语言和构建系统就成了开发循环中的瓶颈。重要的指标是:整个开发反馈周期需要多长时间?其中有多少时间是在等待编译器?如果人类花一小时写代码,漫长的编译周期虽然烦人但尚可忍受。如果一个智能体(Agent)能在几分钟内起草一个合理的变更,然后却要花 15 分钟等待项目从冷启动开始构建,那么编译器就已经从一个“小麻烦”变成了该工作流中的主要成本。

This becomes unbearable when you start using many coding agents in parallel. If you are working on one thing at a time, maybe you pay the cold build cost once and then keep going. But increasingly, that is not how I want to work. I want to spin up multiple worktrees, fork off different lines of work, let agents try things, review the results, and keep the useful ones. In that world, cold start time matters a lot. If every new worktree needs a long Haskell build, or needs careful cache setup, or burns a ton of memory, then every new thread of work starts with a tax. If I want five agents exploring five branches in parallel, that tax multiplies.

当你开始并行使用多个编码智能体时,这种情况就变得无法忍受了。如果你一次只做一件事,也许你只需要支付一次冷启动构建成本,然后继续工作。但越来越多的时候,我不想那样工作。我想启动多个工作树(worktrees),分叉出不同的工作路线,让智能体尝试各种方案,审查结果,并保留有用的部分。在那个世界里,冷启动时间至关重要。如果每一个新的工作树都需要漫长的 Haskell 构建,或者需要精心的缓存设置,或者消耗大量内存,那么每一个新的工作线程都伴随着一种“税”。如果我想让五个智能体并行探索五个分支,这种税就会成倍增加。

People in Haskell talk a lot about caching, Nix, remote builders, and similar tools. Those tools help. We used them. But caching is never perfect, and the amount of effort required to make it feel good enough is itself part of the problem. In practice, parallel AI-assisted development wants cheap, disposable execution contexts. I want to be able to say: fork this off, try the change, run the tests, show me what happened. Our Haskell environment was not cheap enough for that style of work.

Haskell 社区的人经常谈论缓存、Nix、远程构建器和类似的工具。这些工具确实有帮助,我们也用过。但缓存永远不可能是完美的,为了让它“感觉足够好”所付出的努力本身就是问题的一部分。在实践中,并行 AI 辅助开发需要廉价、可丢弃的执行环境。我希望能够说:分叉这个分支,尝试修改,运行测试,告诉我结果。我们的 Haskell 环境对于这种工作方式来说不够廉价。

If everything is cached and you make a small change, you can often get a very fast compile. Sometimes the loop is 20 seconds and that feels great. But that is the best case, and the best case is not what you can optimize the whole system around. The deeper your change goes into core parts of the build plan, the less that story holds. In an agent-heavy workflow, you end up caring a lot more about the cold-start case, the average case, and the deeper-change case. The amount of engineering effort required to make the perfect-cache case happen reliably is itself part of the tax. That became more and more painful.

如果一切都已缓存,并且你只做了微小的改动,通常可以获得非常快的编译速度。有时循环只需 20 秒,感觉很棒。但这只是最佳情况,而你不能围绕最佳情况来优化整个系统。你的改动越深入构建计划的核心部分,这个故事就越站不住脚。在以智能体为主的工作流中,你最终会更关心冷启动情况、平均情况和深度改动情况。为了可靠地实现完美缓存而所需的工程投入本身就是一种“税”。这变得越来越痛苦。

How we moved At Scarf, we started doing all new API work in Python. We deployed a Python API server alongside the Haskell one, routed requests to the right place, and began moving functionality over as we touched it. New API routes go into Python, existing Haskell code keeps running, and over time the new server becomes the main path and our Haskell footprint will shrink. That approach let us move without the risk of a dramatic cutover. It also meant we had to reimplement some core things: authentication, database access, shared models, deployment images, tests, and operational glue. Historically, that kind of setup work would have felt expensive. With LLMs, it wasn’t bad, porting existing code to a new language is quite straightforward for today’s models. The time we got back in our development cycle, from wa

我们是如何迁移的:在 Scarf,我们开始用 Python 进行所有新的 API 开发。我们在 Haskell 服务器旁边部署了一个 Python API 服务器,将请求路由到正确的位置,并随着我们对功能的触及开始将其迁移过去。新的 API 路由进入 Python,现有的 Haskell 代码继续运行,随着时间的推移,新服务器将成为主要路径,我们的 Haskell 占用空间将会缩小。这种方法让我们能够在没有剧烈切换风险的情况下进行迁移。这也意味着我们必须重新实现一些核心内容:身份验证、数据库访问、共享模型、部署镜像、测试和运维胶水代码。从历史上看,这种设置工作会让人觉得代价高昂。但有了 LLM,这并不难,对于今天的模型来说,将现有代码移植到新语言中非常直接。我们在开发周期中节省下来的时间,从……(原文截断)