You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

State hack性能解析:eta展开State# lambda的重要性及GHC-O性能影响

Alright, let's break down the State# eta-expansion "hack" in GHC—this optimization is a classic example of a tradeoff that works wonders for most code but can bite hard in specific cases. Let's start with why it's so crucial for performance, then dig into when and why it backfires.

Why the State# Eta-Expansion Hack Boosts Most Haskell Programs

First, let's clarify what we're talking about: State# is GHC's low-level, opaque token used to track mutable state in IO and ST monads. Functions that manipulate state typically return a lambda that takes a State# token and returns a new token plus a result—something like State# s -> (# State# s, a #).

The "state hack" refers to GHC's optimization where it eta-expands these lambdas by pulling pure computations outside the lambda. For example, take this naive definition:

computeAndStore :: Int -> State# RealWorld -> (# State# RealWorld, Int #)
computeAndStore n = \s ->
  let doubled = n * 2  -- Pure calculation
      squared = doubled * doubled
  in (# s, squared #)

Without the state hack, every time you call the returned lambda (i.e., every time you pass a State# token), GHC would recompute doubled and squared. The hack rewrites this to:

computeAndStore n =
  let doubled = n * 2
      squared = doubled * doubled
  in \s -> (# s, squared #)

Now, doubled and squared are computed once when computeAndStore n is called, not every time the lambda runs. For code where the returned lambda is invoked multiple times (like in loops or repeated state operations), this eliminates redundant computations and cuts down on runtime overhead dramatically.

This is why it's critical for most programs: nearly all IO/ST code includes pure pre-processing or intermediate calculations. The state hack ensures these are only executed when the outer function is called, not on every state transition—saving CPU cycles and reducing memory churn.

Why the State Hack Causes Severe Performance Degradation in Specific Cases

So when does this optimization go wrong? The core issue boils down to broken optimization fusion or premature computation that can't be eliminated.

Let's use a simplified scenario similar to the GHC ticket examples: suppose you have a function that returns a lambda which performs state-dependent operations in a tight loop. The state hack's eta-expansion can break GHC's ability to fuse these state operations into a single, inlineable block of code.

Here's what that might look like:

loop :: Int -> State# RealWorld -> (# State# RealWorld, () #)
loop 0 s = (# s, () #)
loop n s =
  let next = loop (n-1)
  in next s

Without the state hack, GHC can inline next and fuse the loop into a single, tail-recursive block with no lambda overhead. But if the state hack eta-expands loop to pull the lambda outside:

loop n =
  let next = loop (n-1)
  in \s -> next s

Now, each recursive call returns a separate lambda, and GHC can't fuse these into a tight loop. Instead, every iteration involves a function call to the lambda, which adds significant overhead in a loop that runs thousands or millions of times.

Another case is when the "pure" computation inside the lambda actually has hidden dependencies on state (or on values that would be eliminated by later optimizations). For example, if the lambda creates a small temporary object that would normally be eliminated by GHC's strictness or dead-code elimination, eta-expanding it might force that object to be allocated upfront, leading to unnecessary memory pressure and garbage collection overhead.

The key takeaway is: the state hack assumes that pure computations inside the state lambda are safe to precompute, but when those computations are tied to the state flow (or enable critical optimizations like loop fusion), eta-expansion can break the chain of optimizations that GHC relies on to generate efficient code.

内容的提问来源于stack exchange,提问作者sevo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 03:30:08