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 == Nothingif and only if
checkContainsThunks xFor some datatypes however, some thunks are expected. For example, the internal fingertree
Data.Sequence.Sequencemight 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 -> StringShow 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 swhich rely on parametric polymorphism). By default we should therefore only show the "outer layer"; for example, if we have a typeSeq (ST s ())then showTypeOf should just give
Seq, leaving it up to the instance forSTto 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 vianewtype wrappers we provide do depend onTypeable; see below.
Instances80NoThunks, …
NoThunks ByteStringDefined in nothunks-0.3.1 · NoThunks.ClassInstance for string bytestrings
Strict bytestrings shouldn't contain any thunks, but could, due to https://gitlab.haskell.org/ghc/ghc/issues/17290. However, such thunks can't retain any data that they shouldn't, and so it's safe to ignore such thunks.
NoThunks ByteStringDefined in nothunks-0.3.1 · NoThunks.ClassInstance for lazy bytestrings
Defined manually so that it piggy-backs on the one for strict bytestrings.
NoThunks ShortByteStringDefined in nothunks-0.3.1 · NoThunks.ClassInstance for short bytestrings
We have
data ShortByteString = SBS ByteArray#Values of this type consist of a tag followed by an _unboxed_ byte array, which can't contain thunks. Therefore we only check WHNF.
NoThunks IntegerDefined in nothunks-0.3.1 · NoThunks.ClassNoThunks NaturalDefined in nothunks-0.3.1 · NoThunks.ClassNoThunks VoidDefined in nothunks-0.3.1 · NoThunks.ClassNoThunks ThreadIdDefined in nothunks-0.3.1 · NoThunks.ClassNoThunks AllDefined in nothunks-0.3.1 · NoThunks.ClassNoThunks AnyDefined in nothunks-0.3.1 · NoThunks.ClassNoThunks Int16Defined in nothunks-0.3.1 · NoThunks.ClassNoThunks Int32Defined in nothunks-0.3.1 · NoThunks.ClassNoThunks Int64Defined in nothunks-0.3.1 · NoThunks.ClassNoThunks Int8Defined in nothunks-0.3.1 · NoThunks.ClassNoThunks CallStackDefined in nothunks-0.3.1 · NoThunks.ClassSince CallStacks can't retain application data, we don't want to check them for thunks at all
NoThunks Word16Defined in nothunks-0.3.1 · NoThunks.ClassNoThunks Word32Defined in nothunks-0.3.1 · NoThunks.ClassNoThunks Word64Defined in nothunks-0.3.1 · NoThunks.ClassNoThunks Word8Defined in nothunks-0.3.1 · NoThunks.ClassNoThunks BoolDefined in nothunks-0.3.1 · NoThunks.ClassNoThunks CharDefined in nothunks-0.3.1 · NoThunks.ClassNoThunks DoubleDefined in nothunks-0.3.1 · NoThunks.ClassNoThunks FloatDefined in nothunks-0.3.1 · NoThunks.ClassNoThunks IntDefined in nothunks-0.3.1 · NoThunks.ClassNoThunks WordDefined in nothunks-0.3.1 · NoThunks.ClassNoThunks TextDefined in nothunks-0.3.1 · NoThunks.ClassNoThunks TextDefined in nothunks-0.3.1 · NoThunks.ClassNoThunks DayDefined in nothunks-0.3.1 · NoThunks.ClassNoThunks DiffTimeDefined in nothunks-0.3.1 · NoThunks.ClassNoThunks NominalDiffTimeDefined in nothunks-0.3.1 · NoThunks.ClassNoThunks UTCTimeDefined in nothunks-0.3.1 · NoThunks.ClassNoThunks UniversalTimeDefined in nothunks-0.3.1 · NoThunks.ClassNoThunks TimeLocaleDefined in nothunks-0.3.1 · NoThunks.ClassNoThunks LocalTimeDefined in nothunks-0.3.1 · NoThunks.ClassNoThunks TimeOfDayDefined in nothunks-0.3.1 · NoThunks.ClassNoThunks TimeZoneDefined in nothunks-0.3.1 · NoThunks.ClassNoThunks ZonedTimeDefined in nothunks-0.3.1 · NoThunks.ClassNoThunks ()Defined in nothunks-0.3.1 · NoThunks.ClassTypeable a => NoThunks (InspectHeap a)Defined in nothunks-0.3.1 · NoThunks.ClassTypeable a => NoThunks (OnlyCheckWhnf a)Defined in nothunks-0.3.1 · NoThunks.ClassNoThunks (IO a)Defined in nothunks-0.3.1 · NoThunks.ClassWe do not check IO actions for captured thunks by default
See instance for
(a -> b)for detailed discussion.NoThunks (AllowThunk a)Defined in nothunks-0.3.1 · NoThunks.ClassNoThunks (Vector a)Defined in nothunks-0.3.1 · NoThunks.ClassUnboxed vectors can't contain thunks
Implementation note: defined manually rather than using OnlyCheckWhnf due to ghc limitation in deriving via, making it impossible to use with it with data families.
NoThunks a => NoThunks (First a)Defined in nothunks-0.3.1 · NoThunks.ClassNoThunks a => NoThunks (Last a)Defined in nothunks-0.3.1 · NoThunks.ClassNoThunks a => NoThunks (Max a)Defined in nothunks-0.3.1 · NoThunks.ClassNoThunks a => NoThunks (Min a)Defined in nothunks-0.3.1 · NoThunks.ClassNoThunks a => NoThunks (WrappedMonoid a)Defined in nothunks-0.3.1 · NoThunks.ClassNoThunks a => NoThunks (IntMap a)Defined in nothunks-0.3.1 · NoThunks.ClassNoThunks a => NoThunks (Seq a)Defined in nothunks-0.3.1 · NoThunks.ClassNoThunks a => NoThunks (Set a)Defined in nothunks-0.3.1 · NoThunks.ClassNoThunks a => NoThunks (NonEmpty a)Defined in nothunks-0.3.1 · NoThunks.ClassNoThunks a => NoThunks (TVar a)Defined in nothunks-0.3.1 · NoThunks.ClassNoThunks a => NoThunks (Identity a)Defined in nothunks-0.3.1 · NoThunks.ClassNoThunks a => NoThunks (First a)Defined in nothunks-0.3.1 · NoThunks.ClassNoThunks a => NoThunks (Last a)Defined in nothunks-0.3.1 · NoThunks.ClassNoThunks a => NoThunks (Dual a)Defined in nothunks-0.3.1 · NoThunks.ClassNoThunks a => NoThunks (Product a)Defined in nothunks-0.3.1 · NoThunks.ClassNoThunks a => NoThunks (Sum a)Defined in nothunks-0.3.1 · NoThunks.ClassNoThunks a => NoThunks (IORef a)Defined in nothunks-0.3.1 · NoThunks.ClassNoThunks a => NoThunks (MVar a)Defined in nothunks-0.3.1 · NoThunks.ClassNoThunks a => NoThunks (Maybe a)Defined in nothunks-0.3.1 · NoThunks.ClassNoThunks a => NoThunks (Ratio a)Defined in nothunks-0.3.1 · NoThunks.ClassNoThunks a => NoThunks (Vector a)Defined in nothunks-0.3.1 · NoThunks.ClassNoThunks a => NoThunks (a)Defined in nothunks-0.3.1 · NoThunks.ClassNoThunks a => NoThunks [a]Defined in nothunks-0.3.1 · NoThunks.ClassKnownSymbol name => NoThunks (InspectHeapNamed name a)Defined in nothunks-0.3.1 · NoThunks.ClassKnownSymbol name => NoThunks (OnlyCheckWhnfNamed name a)Defined in nothunks-0.3.1 · NoThunks.ClassNoThunks (a -> b)Defined in nothunks-0.3.1 · NoThunks.ClassWe do NOT check function closures for captured thunks by default
Since we have no type information about the values captured in a thunk, the only check we could possibly do is
checkContainsThunks: we can't recursively call noThunks on those captured values, which is problematic if any of those captured values requires a custom instance (for example, data types that depend on laziness, such as Seq).By default we therefore only check if the function is in WHNF, and don't check the captured values at all. If you want a stronger check, you can use
InspectHeap (a -> b)instead.(HasFields s a, Generic a, Typeable a, GWNoThunks s (Rep a)) => NoThunks (AllowThunksIn s a)Defined in nothunks-0.3.1 · NoThunks.Class(NoThunks a, NoThunks b) => NoThunks (Arg a b)Defined in nothunks-0.3.1 · NoThunks.Class(NoThunks a, NoThunks b) => NoThunks (Either a b)Defined in nothunks-0.3.1 · NoThunks.Class(NoThunks a, NoThunks b) => NoThunks (a, b)Defined in nothunks-0.3.1 · NoThunks.Class(NoThunks k, NoThunks v) => NoThunks (Map k v)Defined in nothunks-0.3.1 · NoThunks.ClassNoThunks (f a) => NoThunks (Ap f a)Defined in nothunks-0.3.1 · NoThunks.ClassNoThunks (f a) => NoThunks (Alt f a)Defined in nothunks-0.3.1 · NoThunks.Class(NoThunks a, NoThunks b, NoThunks c) => NoThunks (a, b, c)Defined in nothunks-0.3.1 · NoThunks.Class(NoThunks a, NoThunks b, NoThunks c, NoThunks d) => NoThunks (a, b, c, d)Defined in nothunks-0.3.1 · NoThunks.Class(NoThunks a, NoThunks b, NoThunks c, NoThunks d, NoThunks e) => NoThunks (a, b, c, d, e)Defined in nothunks-0.3.1 · NoThunks.Class(NoThunks a, NoThunks b, NoThunks c, NoThunks d, NoThunks e, NoThunks f) => NoThunks (a, b, c, d, e, f)Defined in nothunks-0.3.1 · NoThunks.Class(NoThunks a, NoThunks b, NoThunks c, NoThunks d, NoThunks e, NoThunks f, NoThunks g) => NoThunks (a, b, c, d, e, f, g)Defined in nothunks-0.3.1 · NoThunks.Class