HORIZON HASKELLDocslts/ghc-9.10.x248f8f02026-10-05Search names, modules, packages, or :: a typeCtrl K

GHC 9.10.3 · lts/ghc-9.10.x · 248f8f0 · 2026-10-05

Modulenothunks-0.3.1Haskell2010

NoThunks.Class

  • 9 types
  • 2 classes
  • 5 values
  • Packagenothunks-0.3.1
  • Exports16
  • LanguageHaskell2010
  • LicenceApache-2.0
  • SourceClass.hs

Check a value for unexpected thunks

6 declarations
classclass NoThunks a where
#

Check a value for unexpected thunks

Methods

  • noThunks :: Context -> a -> IO (Maybe ThunkInfo)

    Check if the argument does not contain any unexpected thunks

    For most datatypes, we should have that

    noThunks ctxt x == Nothing

    if and only if

    checkContainsThunks x

    For some datatypes however, some thunks are expected. For example, the internal fingertree Data.Sequence.Sequence might contain thunks (this is important for the asymptotic complexity of this data structure). However, we should still check that the values in the sequence don't contain any unexpected thunks.

    This means that we need to traverse the sequence, which might force some of the thunks in the tree. In general, it is acceptable for noThunks to force such "expected thunks", as long as it always reports the unexpected thunks.

    The default implementation of noThunks checks that the argument is in WHNF, and if so, adds the type into the context (using showTypeOf or whereFrom if available), and calls wNoThunks. See ThunkInfo for a detailed discussion of the type context.

    See also discussion of caveats listed for checkContainsThunks.

  • wNoThunks :: Context -> a -> IO (Maybe ThunkInfo)

    Check that the argument is in normal form, assuming it is in WHNF.

    The context will already have been extended with the type we're looking at, so all that's left is to look at the thunks inside the type. The default implementation uses GHC Generics to do this.

  • showTypeOf :: Proxy a -> String

    Show type a (to add to the context)

    We try hard to avoid Typeable constraints in this module: there are types with no Typeable instance but with a NoThunks instance (most important example are types such as ST s which rely on parametric polymorphism). By default we should therefore only show the "outer layer"; for example, if we have a type

    Seq (ST s ())

    then showTypeOf should just give Seq, leaving it up to the instance for ST to decide how to implement showTypeOf; this keeps things compositional. The default implementation does precisely this using the metadata that GHC Generics provides.

    For convenience, however, some of the deriving via newtype wrappers we provide do depend on Typeable; see below.

Instances80NoThunks, …
datadata ThunkInfo
#

Information about unexpected thunks

ThunkInfo contains either precise Info about the thunk location or Context to make it easier to debug space leaks. Info is available if

  • GHC-9.4 or newer is used,

  • the code is compiled with -finfo-table-map and is improved if -fdistinct-constructor-tables is used as well.

The Context argument is intended to give a clue to add debugging. For example, suppose we have something of type (Int, [Int]). The various contexts we might get are

Context                  The thunk is..
---------------------------------------------------------------------
["(,)"]                  the pair itself
["Int","(,)"]            the Int in the pair
["List","(,)"]           the [Int] in the pair
["Int","List","(,)"]     an Int in the [Int] in the pair

Note: prior to `ghc-9.6` a list was indicated by `[]`.

Instances1Show
typetype Context = [String]
#

Context where a thunk was found

This is intended to give a hint about which thunk was found. For example, a thunk might be reported with context

["Int", "(,)", "Map", "AppState"]

telling you that you have an AppState containing a Map containing a pair, all of which weren't thunks (were in WHNF), but that pair contained an Int which was a thunk.

typetype Info = String
#

Binding name, type and location information about the thunk, e.g.

fromModel :: Int @ test/Test/NoThunks/Class.hs:198:53-84

Helpers for defining instances

3 declarations

Deriving-via wrappers

6 declarations
newtypenewtype OnlyCheckWhnf a
#

Newtype wrapper for use with deriving via to check for WHNF only

For some types we don't want to check for nested thunks, and we only want check if the argument is in WHNF, not in NF. A typical example are functions; see the instance of (a -> b) for detailed discussion. This should be used sparingly.

Example:

deriving via OnlyCheckWhnf T instance NoThunks T

Constructors

Instances1NoThunks
newtypenewtype InspectHeap a
#

Newtype wrapper for use with deriving via to inspect the heap directly

This bypasses the class instances altogether, and inspects the GHC heap directly, checking that the value does not contain any thunks anywhere. Since we can do this without any type classes instances, this is useful for types that contain fields for which NoThunks instances are not available.

Since the primary use case for InspectHeap then is to give instances for NoThunks from third party libraries, we also don't want to rely on a Generic instance, which may likewise not be available. Instead, we will rely on Typeable, which is available for all types. However, as showTypeOf explains, requiring Typeable may not always be suitable; if it isn't, InspectHeapNamed can be used.

Example:

deriving via InspectHeap T instance NoThunks T

Constructors

Instances1NoThunks
newtypenewtype AllowThunk a
#

Newtype wrapper for values that should be allowed to be a thunk

This should be used VERY sparingly, and should ONLY be used on values (or, even rarer, types) which you are SURE cannot retain any data that they shouldn't. Bear in mind allowing a value of type T to be a thunk might cause a value of type S to be retained if T was computed from S.

Constructors

Instances1NoThunks
newtypenewtype AllowThunksIn (fields :: [Symbol]) a
#

Newtype wrapper for records where some of the fields are allowed to be thunks.

Example:

deriving via AllowThunksIn '["foo","bar"] T instance NoThunks T

This will create an instance that skips the thunk checks for the "foo" and "bar" fields.

Constructors

Instances1NoThunks

Generic class

1 declaration
classclass GWNoThunks (a :: [Symbol]) (f :: Type -> Type) where
#

Generic infrastructure for checking for unexpected thunks

The a argument records which record fields are allowed to contain thunks; see AllowThunksIn and GWRecordField, below.

Methods

Instances9GWNoThunks, …