├── .git-blame-ignore-revs ├── .github └── workflows │ └── haskell-ci.yml ├── .gitignore ├── Control └── DeepSeq.hs ├── LICENSE ├── README.md ├── Setup.hs ├── changelog.md ├── deepseq.cabal ├── generate-nfdata-tuple.hs └── tests └── Main.hs /.git-blame-ignore-revs: -------------------------------------------------------------------------------- 1 | 17a9895f94d3e86c55ee4a57affdf0b15db39aab 2 | -------------------------------------------------------------------------------- /.github/workflows/haskell-ci.yml: -------------------------------------------------------------------------------- 1 | # This GitHub workflow config has been generated by a script via 2 | # 3 | # haskell-ci './deepseq.cabal' '-o' './.github/workflows/haskell-ci.yml' 4 | # 5 | # To regenerate the script (for example after adjusting tested-with) run 6 | # 7 | # haskell-ci regenerate 8 | # 9 | # For more information, see https://github.com/haskell-CI/haskell-ci 10 | # 11 | # version: 0.19.20240708 12 | # 13 | # REGENDATA ("0.19.20240708",["./deepseq.cabal","-o","./.github/workflows/haskell-ci.yml"]) 14 | # 15 | name: Haskell-CI 16 | on: 17 | - push 18 | - pull_request 19 | jobs: 20 | linux: 21 | name: Haskell-CI - Linux - ${{ matrix.compiler }} 22 | runs-on: ubuntu-20.04 23 | timeout-minutes: 24 | 60 25 | container: 26 | image: buildpack-deps:jammy 27 | continue-on-error: ${{ matrix.allow-failure }} 28 | strategy: 29 | matrix: 30 | include: 31 | - compiler: ghc-9.10.1 32 | compilerKind: ghc 33 | compilerVersion: 9.10.1 34 | setup-method: ghcup 35 | allow-failure: false 36 | - compiler: ghc-9.8.2 37 | compilerKind: ghc 38 | compilerVersion: 9.8.2 39 | setup-method: ghcup 40 | allow-failure: false 41 | - compiler: ghc-9.6.6 42 | compilerKind: ghc 43 | compilerVersion: 9.6.6 44 | setup-method: ghcup 45 | allow-failure: false 46 | - compiler: ghc-9.4.8 47 | compilerKind: ghc 48 | compilerVersion: 9.4.8 49 | setup-method: ghcup 50 | allow-failure: false 51 | - compiler: ghc-9.2.8 52 | compilerKind: ghc 53 | compilerVersion: 9.2.8 54 | setup-method: ghcup 55 | allow-failure: false 56 | - compiler: ghc-9.0.2 57 | compilerKind: ghc 58 | compilerVersion: 9.0.2 59 | setup-method: ghcup 60 | allow-failure: false 61 | - compiler: ghc-8.10.7 62 | compilerKind: ghc 63 | compilerVersion: 8.10.7 64 | setup-method: ghcup 65 | allow-failure: false 66 | - compiler: ghc-8.8.4 67 | compilerKind: ghc 68 | compilerVersion: 8.8.4 69 | setup-method: ghcup 70 | allow-failure: false 71 | - compiler: ghc-8.6.5 72 | compilerKind: ghc 73 | compilerVersion: 8.6.5 74 | setup-method: ghcup 75 | allow-failure: false 76 | fail-fast: false 77 | steps: 78 | - name: apt 79 | run: | 80 | apt-get update 81 | apt-get install -y --no-install-recommends gnupg ca-certificates dirmngr curl git software-properties-common libtinfo5 82 | mkdir -p "$HOME/.ghcup/bin" 83 | curl -sL https://downloads.haskell.org/ghcup/0.1.30.0/x86_64-linux-ghcup-0.1.30.0 > "$HOME/.ghcup/bin/ghcup" 84 | chmod a+x "$HOME/.ghcup/bin/ghcup" 85 | "$HOME/.ghcup/bin/ghcup" install ghc "$HCVER" || (cat "$HOME"/.ghcup/logs/*.* && false) 86 | "$HOME/.ghcup/bin/ghcup" install cabal 3.12.1.0 || (cat "$HOME"/.ghcup/logs/*.* && false) 87 | env: 88 | HCKIND: ${{ matrix.compilerKind }} 89 | HCNAME: ${{ matrix.compiler }} 90 | HCVER: ${{ matrix.compilerVersion }} 91 | - name: Set PATH and environment variables 92 | run: | 93 | echo "$HOME/.cabal/bin" >> $GITHUB_PATH 94 | echo "LANG=C.UTF-8" >> "$GITHUB_ENV" 95 | echo "CABAL_DIR=$HOME/.cabal" >> "$GITHUB_ENV" 96 | echo "CABAL_CONFIG=$HOME/.cabal/config" >> "$GITHUB_ENV" 97 | HCDIR=/opt/$HCKIND/$HCVER 98 | HC=$("$HOME/.ghcup/bin/ghcup" whereis ghc "$HCVER") 99 | HCPKG=$(echo "$HC" | sed 's#ghc$#ghc-pkg#') 100 | HADDOCK=$(echo "$HC" | sed 's#ghc$#haddock#') 101 | echo "HC=$HC" >> "$GITHUB_ENV" 102 | echo "HCPKG=$HCPKG" >> "$GITHUB_ENV" 103 | echo "HADDOCK=$HADDOCK" >> "$GITHUB_ENV" 104 | echo "CABAL=$HOME/.ghcup/bin/cabal-3.12.1.0 -vnormal+nowrap" >> "$GITHUB_ENV" 105 | HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\d+)\.(\d+)\.(\d+)(\.(\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))') 106 | echo "HCNUMVER=$HCNUMVER" >> "$GITHUB_ENV" 107 | echo "ARG_TESTS=--enable-tests" >> "$GITHUB_ENV" 108 | echo "ARG_BENCH=--enable-benchmarks" >> "$GITHUB_ENV" 109 | echo "HEADHACKAGE=false" >> "$GITHUB_ENV" 110 | echo "ARG_COMPILER=--$HCKIND --with-compiler=$HC" >> "$GITHUB_ENV" 111 | echo "GHCJSARITH=0" >> "$GITHUB_ENV" 112 | env: 113 | HCKIND: ${{ matrix.compilerKind }} 114 | HCNAME: ${{ matrix.compiler }} 115 | HCVER: ${{ matrix.compilerVersion }} 116 | - name: env 117 | run: | 118 | env 119 | - name: write cabal config 120 | run: | 121 | mkdir -p $CABAL_DIR 122 | cat >> $CABAL_CONFIG <> $CABAL_CONFIG < cabal-plan.xz 155 | echo 'f62ccb2971567a5f638f2005ad3173dba14693a45154c1508645c52289714cb2 cabal-plan.xz' | sha256sum -c - 156 | xz -d < cabal-plan.xz > $HOME/.cabal/bin/cabal-plan 157 | rm -f cabal-plan.xz 158 | chmod a+x $HOME/.cabal/bin/cabal-plan 159 | cabal-plan --version 160 | - name: checkout 161 | uses: actions/checkout@v4 162 | with: 163 | path: source 164 | - name: initial cabal.project for sdist 165 | run: | 166 | touch cabal.project 167 | echo "packages: $GITHUB_WORKSPACE/source/." >> cabal.project 168 | cat cabal.project 169 | - name: sdist 170 | run: | 171 | mkdir -p sdist 172 | $CABAL sdist all --output-dir $GITHUB_WORKSPACE/sdist 173 | - name: unpack 174 | run: | 175 | mkdir -p unpacked 176 | find sdist -maxdepth 1 -type f -name '*.tar.gz' -exec tar -C $GITHUB_WORKSPACE/unpacked -xzvf {} \; 177 | - name: generate cabal.project 178 | run: | 179 | PKGDIR_deepseq="$(find "$GITHUB_WORKSPACE/unpacked" -maxdepth 1 -type d -regex '.*/deepseq-[0-9.]*')" 180 | echo "PKGDIR_deepseq=${PKGDIR_deepseq}" >> "$GITHUB_ENV" 181 | rm -f cabal.project cabal.project.local 182 | touch cabal.project 183 | touch cabal.project.local 184 | echo "packages: ${PKGDIR_deepseq}" >> cabal.project 185 | echo "package deepseq" >> cabal.project 186 | echo " ghc-options: -Werror=missing-methods" >> cabal.project 187 | cat >> cabal.project <> cabal.project.local 190 | cat cabal.project 191 | cat cabal.project.local 192 | - name: dump install plan 193 | run: | 194 | $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dry-run all 195 | cabal-plan 196 | - name: restore cache 197 | uses: actions/cache/restore@v4 198 | with: 199 | key: ${{ runner.os }}-${{ matrix.compiler }}-${{ github.sha }} 200 | path: ~/.cabal/store 201 | restore-keys: ${{ runner.os }}-${{ matrix.compiler }}- 202 | - name: install dependencies 203 | run: | 204 | $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks --dependencies-only -j2 all 205 | $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dependencies-only -j2 all 206 | - name: build w/o tests 207 | run: | 208 | $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all 209 | - name: build 210 | run: | 211 | $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH all --write-ghc-environment-files=always 212 | - name: tests 213 | run: | 214 | $CABAL v2-test $ARG_COMPILER $ARG_TESTS $ARG_BENCH all --test-show-details=direct 215 | - name: cabal check 216 | run: | 217 | cd ${PKGDIR_deepseq} || false 218 | ${CABAL} -vnormal check 219 | - name: haddock 220 | run: | 221 | $CABAL v2-haddock --disable-documentation --haddock-all $ARG_COMPILER --with-haddock $HADDOCK $ARG_TESTS $ARG_BENCH all 222 | - name: unconstrained build 223 | run: | 224 | rm -f cabal.project.local 225 | $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all 226 | - name: save cache 227 | uses: actions/cache/save@v4 228 | if: always() 229 | with: 230 | key: ${{ runner.os }}-${{ matrix.compiler }}-${{ github.sha }} 231 | path: ~/.cabal/store 232 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | GNUmakefile 2 | /dist-* 3 | ghc.mk 4 | -------------------------------------------------------------------------------- /Control/DeepSeq.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE CPP #-} 2 | {-# LANGUAGE DefaultSignatures #-} 3 | {-# LANGUAGE EmptyCase #-} 4 | {-# LANGUAGE FlexibleContexts #-} 5 | {-# LANGUAGE FlexibleInstances #-} 6 | {-# LANGUAGE MultiParamTypeClasses #-} 7 | {-# LANGUAGE PolyKinds #-} 8 | {-# LANGUAGE QuantifiedConstraints #-} 9 | {-# LANGUAGE Trustworthy #-} 10 | {-# LANGUAGE TypeFamilies #-} 11 | {-# LANGUAGE TypeOperators #-} 12 | 13 | #if __GLASGOW_HASKELL__ >= 811 && __GLASGOW_HASKELL__ < 901 14 | -- For the Option instance (https://gitlab.haskell.org/ghc/ghc/issues/15028) 15 | {-# OPTIONS_GHC -Wno-deprecations #-} 16 | #endif 17 | 18 | ----------------------------------------------------------------------------- 19 | 20 | -- | 21 | -- Module : Control.DeepSeq 22 | -- Copyright : (c) The University of Glasgow 2001-2009 23 | -- License : BSD-style (see the file LICENSE) 24 | -- 25 | -- Maintainer : libraries@haskell.org 26 | -- Stability : stable 27 | -- Portability : portable 28 | -- 29 | -- This module provides overloaded functions, such as 'deepseq' and 30 | -- 'rnf', for fully evaluating data structures (that is, evaluating to 31 | -- \"Normal Form\"). 32 | -- 33 | -- A typical use is to prevent resource leaks in lazy IO programs, by 34 | -- forcing all characters from a file to be read. For example: 35 | -- 36 | -- > import System.IO 37 | -- > import Control.DeepSeq 38 | -- > import Control.Exception (evaluate) 39 | -- > 40 | -- > readFile' :: FilePath -> IO String 41 | -- > readFile' fn = do 42 | -- > h <- openFile fn ReadMode 43 | -- > s <- hGetContents h 44 | -- > evaluate (rnf s) 45 | -- > hClose h 46 | -- > return s 47 | -- 48 | -- __Note__: The example above should rather be written in terms of 49 | -- 'Control.Exception.bracket' to ensure releasing file-descriptors in 50 | -- a timely matter (see the description of 'force' for an example). 51 | -- 52 | -- 'deepseq' differs from 'seq' as it traverses data structures deeply, 53 | -- for example, 'seq' will evaluate only to the first constructor in 54 | -- the list: 55 | -- 56 | -- > > [1,2,undefined] `seq` 3 57 | -- > 3 58 | -- 59 | -- While 'deepseq' will force evaluation of all the list elements: 60 | -- 61 | -- > > [1,2,undefined] `deepseq` 3 62 | -- > *** Exception: Prelude.undefined 63 | -- 64 | -- Another common use is to ensure any exceptions hidden within lazy 65 | -- fields of a data structure do not leak outside the scope of the 66 | -- exception handler, or to force evaluation of a data structure in one 67 | -- thread, before passing to another thread (preventing work moving to 68 | -- the wrong threads). 69 | -- 70 | -- @since 1.1.0.0 71 | module Control.DeepSeq ( 72 | -- * 'NFData' class 73 | NFData (rnf), 74 | 75 | -- * Helper functions 76 | deepseq, 77 | force, 78 | ($!!), 79 | (<$!!>), 80 | rwhnf, 81 | Unit(..), 82 | 83 | -- * Liftings of the 'NFData' class 84 | 85 | -- ** For unary constructors 86 | NFData1 (liftRnf), 87 | rnf1, 88 | 89 | -- ** For binary constructors 90 | NFData2 (liftRnf2), 91 | rnf2, 92 | ) where 93 | 94 | import Control.Applicative 95 | import Control.Concurrent (MVar, ThreadId) 96 | import Control.Exception (MaskingState (..)) 97 | import Data.Complex 98 | import Data.Fixed 99 | import Data.Functor.Compose 100 | import Data.Functor.Identity (Identity (..)) 101 | import qualified Data.Functor.Product as Functor 102 | import qualified Data.Functor.Sum as Functor 103 | import Data.IORef 104 | import Data.Int 105 | import Data.List.NonEmpty (NonEmpty (..)) 106 | import Data.Monoid as Mon 107 | import Data.Ord (Down (Down)) 108 | import Data.Proxy (Proxy (Proxy)) 109 | import Data.Ratio 110 | import Data.STRef 111 | import Data.Semigroup as Semi 112 | import Data.Type.Equality ((:~:), (:~~:)) 113 | import Data.Typeable (TyCon, TypeRep, rnfTyCon, rnfTypeRep) 114 | import Data.Unique (Unique) 115 | import Data.Version 116 | import Data.Void (Void, absurd) 117 | import Data.Word 118 | import Foreign.C.Types 119 | import Foreign.Ptr 120 | import GHC.Arr (Array) 121 | import qualified GHC.Arr 122 | import GHC.Fingerprint.Type (Fingerprint (..)) 123 | import GHC.Generics 124 | import GHC.Stack.Types (CallStack (..), SrcLoc (..)) 125 | import Numeric.Natural (Natural) 126 | import System.Exit (ExitCode (..)) 127 | import System.Mem.StableName (StableName) 128 | import qualified Type.Reflection as Reflection 129 | 130 | #ifdef MIN_VERSION_ghc_prim 131 | #if MIN_VERSION_ghc_prim(0,7,0) 132 | import GHC.Tuple (Solo (..)) 133 | #endif 134 | #endif 135 | 136 | #if MIN_VERSION_base(4,17,0) 137 | import Data.Array.Byte (ByteArray(..), MutableByteArray(..)) 138 | #endif 139 | 140 | -- | Hidden internal type-class 141 | class GNFData arity f where 142 | grnf :: RnfArgs arity a -> f a -> () 143 | 144 | instance GNFData arity V1 where 145 | grnf _ x = case x of {} 146 | 147 | data Zero 148 | 149 | data One 150 | 151 | data family RnfArgs arity a 152 | 153 | data instance RnfArgs Zero a = RnfArgs0 154 | 155 | newtype instance RnfArgs One a = RnfArgs1 (a -> ()) 156 | 157 | instance GNFData arity U1 where 158 | grnf _ U1 = () 159 | 160 | instance NFData a => GNFData arity (K1 i a) where 161 | grnf _ = rnf . unK1 162 | {-# INLINEABLE grnf #-} 163 | 164 | instance GNFData arity a => GNFData arity (M1 i c a) where 165 | grnf args = grnf args . unM1 166 | {-# INLINEABLE grnf #-} 167 | 168 | instance GNFData arity (URec a) where 169 | grnf _ = rwhnf -- Every URec data instance consists of a single data 170 | -- constructor containing a single strict field, so reducing 171 | -- any URec instance to WHNF suffices to reduce it to NF. 172 | {-# INLINEABLE grnf #-} 173 | 174 | instance (GNFData arity a, GNFData arity b) => GNFData arity (a :*: b) where 175 | grnf args (x :*: y) = grnf args x `seq` grnf args y 176 | {-# INLINEABLE grnf #-} 177 | 178 | instance (GNFData arity a, GNFData arity b) => GNFData arity (a :+: b) where 179 | grnf args (L1 x) = grnf args x 180 | grnf args (R1 x) = grnf args x 181 | {-# INLINEABLE grnf #-} 182 | 183 | instance GNFData One Par1 where 184 | grnf (RnfArgs1 r) = r . unPar1 185 | 186 | instance NFData1 f => GNFData One (Rec1 f) where 187 | grnf (RnfArgs1 r) = liftRnf r . unRec1 188 | 189 | instance (NFData1 f, GNFData One g) => GNFData One (f :.: g) where 190 | grnf args = liftRnf (grnf args) . unComp1 191 | 192 | infixr 0 $!! 193 | 194 | infixr 0 `deepseq` 195 | 196 | -- | 'deepseq': fully evaluates the first argument, before returning the 197 | -- second. 198 | -- 199 | -- The name 'deepseq' is used to illustrate the relationship to 'seq': 200 | -- where 'seq' is shallow in the sense that it only evaluates the top 201 | -- level of its argument, 'deepseq' traverses the entire data structure 202 | -- evaluating it completely. 203 | -- 204 | -- 'deepseq' can be useful for forcing pending exceptions, 205 | -- eradicating space leaks, or forcing lazy I/O to happen. It is 206 | -- also useful in conjunction with parallel Strategies (see the 207 | -- @parallel@ package). 208 | -- 209 | -- There is no guarantee about the ordering of evaluation. The 210 | -- implementation may evaluate the components of the structure in 211 | -- any order or in parallel. To impose an actual order on 212 | -- evaluation, use 'pseq' from "Control.Parallel" in the 213 | -- @parallel@ package. 214 | -- 215 | -- @since 1.1.0.0 216 | deepseq :: NFData a => a -> b -> b 217 | deepseq a b = rnf a `seq` b 218 | 219 | -- | The deep analogue of '$!'. @f $!! x@ fully evaluates @x@ 220 | -- before returning @f x@. 221 | -- 222 | -- There is no guarantee about the ordering of evaluation. 223 | -- @f x@ may be evaluated before @x@ is fully evaluated. 224 | -- To impose an actual order on evaluation, use 'pseq' from 225 | -- "Control.Parallel" in the @parallel@ package. 226 | -- 227 | -- @since 1.2.0.0 228 | ($!!) :: (NFData a) => (a -> b) -> a -> b 229 | f $!! x = x `deepseq` f x 230 | 231 | -- | A variant of 'deepseq' that is useful in some circumstances: 232 | -- 233 | -- > force x = x `deepseq` x 234 | -- 235 | -- @force x@ fully evaluates @x@, and then returns it. Note that 236 | -- @force x@ only performs evaluation when the value of @force x@ 237 | -- itself is demanded, so essentially it turns shallow evaluation into 238 | -- deep evaluation. 239 | -- 240 | -- 'force' can be conveniently used in combination with @ViewPatterns@: 241 | -- 242 | -- > {-# LANGUAGE BangPatterns, ViewPatterns #-} 243 | -- > import Control.DeepSeq 244 | -- > 245 | -- > someFun :: ComplexData -> SomeResult 246 | -- > someFun (force -> !arg) = {- 'arg' will be fully evaluated -} 247 | -- 248 | -- Another useful application is to combine 'force' with 249 | -- 'Control.Exception.evaluate' in order to force deep evaluation 250 | -- relative to other 'IO' operations: 251 | -- 252 | -- > import Control.Exception (evaluate) 253 | -- > import Control.DeepSeq 254 | -- > 255 | -- > main = do 256 | -- > result <- evaluate $ force $ pureComputation 257 | -- > {- 'result' will be fully evaluated at this point -} 258 | -- > return () 259 | -- 260 | -- Finally, here's an exception safe variant of the @readFile'@ example: 261 | -- 262 | -- > readFile' :: FilePath -> IO String 263 | -- > readFile' fn = bracket (openFile fn ReadMode) hClose $ \h -> 264 | -- > evaluate . force =<< hGetContents h 265 | -- 266 | -- @since 1.2.0.0 267 | force :: (NFData a) => a -> a 268 | force x = x `deepseq` x 269 | 270 | -- | Deeply strict version of 'Control.Applicative.<$>'. 271 | -- 272 | -- @since 1.4.3.0 273 | (<$!!>) :: (Monad m, NFData b) => (a -> b) -> m a -> m b 274 | f <$!!> m = m >>= \x -> pure $!! f x 275 | 276 | infixl 4 <$!!> 277 | 278 | -- | Reduce to weak head normal form 279 | -- 280 | -- Equivalent to @\\x -> 'seq' x ()@. 281 | -- 282 | -- Useful for defining 'NFData' for types for which NF=WHNF holds. 283 | -- 284 | -- > data T = C1 | C2 | C3 285 | -- > instance NFData T where rnf = rwhnf 286 | -- 287 | -- @since 1.4.3.0 288 | rwhnf :: a -> () 289 | rwhnf = (`seq` ()) 290 | {-# INLINE rwhnf #-} 291 | 292 | -- Note: the 'rwhnf' is defined point-free to help aggressive inlining 293 | 294 | -- | A class of types that can be fully evaluated. 295 | -- 296 | -- @since 1.1.0.0 297 | class NFData a where 298 | -- | 'rnf' should reduce its argument to normal form (that is, fully 299 | -- evaluate all sub-components), and then return '()'. 300 | -- 301 | -- === 'Generic' 'NFData' deriving 302 | -- 303 | -- Starting with GHC 7.2, you can automatically derive instances 304 | -- for types possessing a 'Generic' instance. 305 | -- 306 | -- Note: 'Generic1' can be auto-derived starting with GHC 7.4 307 | -- 308 | -- > {-# LANGUAGE DeriveGeneric #-} 309 | -- > 310 | -- > import GHC.Generics (Generic, Generic1) 311 | -- > import Control.DeepSeq 312 | -- > 313 | -- > data Foo a = Foo a String 314 | -- > deriving (Eq, Generic, Generic1) 315 | -- > 316 | -- > instance NFData a => NFData (Foo a) 317 | -- > instance NFData1 Foo 318 | -- > 319 | -- > data Colour = Red | Green | Blue 320 | -- > deriving Generic 321 | -- > 322 | -- > instance NFData Colour 323 | -- 324 | -- Starting with GHC 7.10, the example above can be written more 325 | -- concisely by enabling the new @DeriveAnyClass@ extension: 326 | -- 327 | -- > {-# LANGUAGE DeriveGeneric, DeriveAnyClass #-} 328 | -- > 329 | -- > import GHC.Generics (Generic) 330 | -- > import Control.DeepSeq 331 | -- > 332 | -- > data Foo a = Foo a String 333 | -- > deriving (Eq, Generic, Generic1, NFData, NFData1) 334 | -- > 335 | -- > data Colour = Red | Green | Blue 336 | -- > deriving (Generic, NFData) 337 | -- > 338 | -- 339 | -- === Compatibility with previous @deepseq@ versions 340 | -- 341 | -- Prior to version 1.4.0.0, the default implementation of the 'rnf' 342 | -- method was defined as 343 | -- 344 | -- @'rnf' a = 'seq' a ()@ 345 | -- 346 | -- However, starting with @deepseq-1.4.0.0@, the default 347 | -- implementation is based on @DefaultSignatures@ allowing for 348 | -- more accurate auto-derived 'NFData' instances. If you need the 349 | -- previously used exact default 'rnf' method implementation 350 | -- semantics, use 351 | -- 352 | -- > instance NFData Colour where rnf x = seq x () 353 | -- 354 | -- or alternatively 355 | -- 356 | -- > instance NFData Colour where rnf = rwhnf 357 | -- 358 | -- or 359 | -- 360 | -- > {-# LANGUAGE BangPatterns #-} 361 | -- > instance NFData Colour where rnf !_ = () 362 | rnf :: a -> () 363 | default rnf :: (Generic a, GNFData Zero (Rep a)) => a -> () 364 | rnf = grnf RnfArgs0 . from 365 | 366 | -- | A class of functors that can be fully evaluated. 367 | -- 368 | -- In `deepseq-1.5.0.0` this class was updated to include superclasses. 369 | -- 370 | -- @since 1.4.3.0 371 | class (forall a. NFData a => NFData (f a)) => NFData1 f where 372 | -- | 'liftRnf' should reduce its argument to normal form (that is, fully 373 | -- evaluate all sub-components), given an argument to reduce @a@ arguments, 374 | -- and then return '()'. 375 | -- 376 | -- See 'rnf' for the generic deriving. 377 | liftRnf :: (a -> ()) -> f a -> () 378 | default liftRnf :: (Generic1 f, GNFData One (Rep1 f)) => (a -> ()) -> f a -> () 379 | liftRnf r = grnf (RnfArgs1 r) . from1 380 | 381 | -- | Lift the standard 'rnf' function through the type constructor. 382 | -- 383 | -- @since 1.4.3.0 384 | rnf1 :: (NFData1 f, NFData a) => f a -> () 385 | rnf1 = liftRnf rnf 386 | 387 | -- | A class of bifunctors that can be fully evaluated. 388 | -- 389 | -- In `deepseq-1.5.0.0` this class was updated to include superclasses. 390 | -- 391 | -- @since 1.4.3.0 392 | class (forall a. NFData a => NFData1 (p a)) => NFData2 p where 393 | -- | 'liftRnf2' should reduce its argument to normal form (that 394 | -- is, fully evaluate all sub-components), given functions to 395 | -- reduce @a@ and @b@ arguments respectively, and then return '()'. 396 | -- 397 | -- __Note__: Unlike for the unary 'liftRnf', there is currently no 398 | -- support for generically deriving 'liftRnf2'. 399 | liftRnf2 :: (a -> ()) -> (b -> ()) -> p a b -> () 400 | 401 | -- | Lift the standard 'rnf' function through the type constructor. 402 | -- 403 | -- @since 1.4.3.0 404 | rnf2 :: (NFData2 p, NFData a, NFData b) => p a b -> () 405 | rnf2 = liftRnf2 rnf rnf 406 | 407 | -- | A monoid with @(<>) = seq@. 408 | -- 409 | -- Its purpose is to allow reducing structures to normal form using 410 | -- 'foldMap'-like functions. 411 | -- 412 | -- ==== __Examples__ 413 | -- 414 | -- @ 415 | -- data Three a = Three a a a 416 | -- 417 | -- instance Foldable Three where 418 | -- foldMap f (Three x1 x2 x3) = f x1 <> f x2 <> f x3 419 | -- 420 | -- instance NFData a => NFData (Three a) where 421 | -- rnf = runUnit . foldMap (Unit . rnf) 422 | -- @ 423 | -- 424 | -- @ 425 | -- data Tree a b 426 | -- = NodeA a [Tree a b] 427 | -- | NodeB b [Tree a b] 428 | -- 429 | -- foldMapTree :: Monoid m => (a -> m) -> (b -> m) -> Tree a b -> m 430 | -- foldMapTree f g = go 431 | -- where 432 | -- go (NodeA x ts) = f x <> foldMap go ts 433 | -- go (NodeB y ts) = g y <> foldMap go ts 434 | -- 435 | -- instance NFData2 Tree where 436 | -- liftRnf2 r r' = runUnit . foldMapTree (Unit . r) (Unit . r') 437 | -- @ 438 | newtype Unit = Unit { runUnit :: () } 439 | 440 | instance Semigroup Unit where 441 | (<>) = seq 442 | 443 | instance Monoid Unit where 444 | mempty = Unit () 445 | 446 | instance NFData Int where rnf = rwhnf 447 | 448 | instance NFData Word where rnf = rwhnf 449 | 450 | instance NFData Integer where rnf = rwhnf 451 | 452 | instance NFData Float where rnf = rwhnf 453 | 454 | instance NFData Double where rnf = rwhnf 455 | 456 | instance NFData Char where rnf = rwhnf 457 | 458 | instance NFData Bool where rnf = rwhnf 459 | 460 | instance NFData Ordering where rnf = rwhnf 461 | 462 | instance NFData () where rnf = rwhnf 463 | 464 | instance NFData Int8 where rnf = rwhnf 465 | 466 | instance NFData Int16 where rnf = rwhnf 467 | 468 | instance NFData Int32 where rnf = rwhnf 469 | 470 | instance NFData Int64 where rnf = rwhnf 471 | 472 | instance NFData Word8 where rnf = rwhnf 473 | 474 | instance NFData Word16 where rnf = rwhnf 475 | 476 | instance NFData Word32 where rnf = rwhnf 477 | 478 | instance NFData Word64 where rnf = rwhnf 479 | 480 | -- | @since 1.4.4.0 481 | instance NFData MaskingState where rnf = rwhnf 482 | 483 | -- | @since 1.4.0.0 484 | instance NFData (Proxy a) where rnf Proxy = () 485 | 486 | -- | @since 1.4.3.0 487 | instance NFData1 Proxy where liftRnf _ Proxy = () 488 | 489 | -- | @since 1.4.3.0 490 | instance NFData (a :~: b) where rnf = rwhnf 491 | 492 | -- | @since 1.4.3.0 493 | instance NFData1 ((:~:) a) where liftRnf _ = rwhnf 494 | 495 | -- | @since 1.4.3.0 496 | instance NFData2 (:~:) where liftRnf2 _ _ = rwhnf 497 | 498 | -- | @since 1.4.3.0 499 | instance NFData (a :~~: b) where rnf = rwhnf 500 | 501 | -- | @since 1.4.3.0 502 | instance NFData1 ((:~~:) a) where liftRnf _ = rwhnf 503 | 504 | -- | @since 1.4.3.0 505 | instance NFData2 (:~~:) where liftRnf2 _ _ = rwhnf 506 | 507 | -- | @since 1.4.0.0 508 | instance NFData a => NFData (Identity a) where 509 | rnf = rnf1 510 | 511 | -- | @since 1.4.3.0 512 | instance NFData1 Identity where 513 | liftRnf r = r . runIdentity 514 | 515 | -- | Defined as @'rnf' = 'absurd'@. 516 | -- 517 | -- @since 1.4.0.0 518 | instance NFData Void where 519 | rnf = absurd 520 | 521 | -- | @since 1.4.0.0 522 | instance NFData Natural where rnf = rwhnf 523 | 524 | -- | @since 1.3.0.0 525 | instance NFData (Fixed a) where rnf = rwhnf 526 | 527 | -- | @since 1.4.3.0 528 | instance NFData1 Fixed where liftRnf _ = rwhnf 529 | 530 | -- | This instance is for convenience and consistency with 'seq'. 531 | -- This assumes that WHNF is equivalent to NF for functions. 532 | -- 533 | -- @since 1.3.0.0 534 | instance NFData (a -> b) where rnf = rwhnf 535 | 536 | -- Rational and complex numbers. 537 | 538 | -- | Available on @base >=4.9@ 539 | -- 540 | -- @since 1.4.3.0 541 | instance NFData1 Ratio where 542 | liftRnf r x = r (numerator x) `seq` r (denominator x) 543 | 544 | -- | @since 1.4.3.0 545 | instance (NFData1 f, NFData1 g) => NFData1 (Compose f g) where 546 | liftRnf r = liftRnf (liftRnf r) . getCompose 547 | 548 | -- | Note: in @deepseq-1.5.0.0@ this instance's superclasses were changed. 549 | -- 550 | -- @since 1.4.3.0 551 | instance (NFData (f (g a))) => NFData (Compose f g a) where 552 | rnf (Compose fga) = rnf fga 553 | 554 | -- | @since 1.4.3.0 555 | instance (NFData1 f, NFData1 g) => NFData1 (Functor.Sum f g) where 556 | liftRnf rnf0 (Functor.InL l) = liftRnf rnf0 l 557 | liftRnf rnf0 (Functor.InR r) = liftRnf rnf0 r 558 | 559 | -- | Note: in @deepseq-1.5.0.0@ this instance's superclasses were changed. 560 | -- 561 | -- @since 1.4.3.0 562 | instance (NFData (f a), NFData (g a)) => NFData (Functor.Sum f g a) where 563 | rnf (Functor.InL fa) = rnf fa 564 | rnf (Functor.InR ga) = rnf ga 565 | 566 | -- | @since 1.4.3.0 567 | instance (NFData1 f, NFData1 g) => NFData1 (Functor.Product f g) where 568 | liftRnf rnf0 (Functor.Pair f g) = liftRnf rnf0 f `seq` liftRnf rnf0 g 569 | 570 | -- | Note: in @deepseq-1.5.0.0@ this instance's superclasses were changed. 571 | -- 572 | -- @since 1.4.3.0 573 | instance (NFData (f a), NFData (g a)) => NFData (Functor.Product f g a) where 574 | rnf (Functor.Pair fa ga) = rnf fa `seq` rnf ga 575 | 576 | instance NFData a => NFData (Ratio a) where 577 | rnf x = rnf (numerator x, denominator x) 578 | 579 | instance (NFData a) => NFData (Complex a) where 580 | rnf (x :+ y) = rnf x `seq` rnf y `seq` () 581 | 582 | instance NFData a => NFData (Maybe a) where rnf = rnf1 583 | 584 | -- | @since 1.4.3.0 585 | instance NFData1 Maybe where 586 | liftRnf _r Nothing = () 587 | liftRnf r (Just x) = r x 588 | 589 | instance (NFData a, NFData b) => NFData (Either a b) where rnf = rnf1 590 | 591 | -- | @since 1.4.3.0 592 | instance (NFData a) => NFData1 (Either a) where liftRnf = liftRnf2 rnf 593 | 594 | -- | @since 1.4.3.0 595 | instance NFData2 Either where 596 | liftRnf2 l _r (Left x) = l x 597 | liftRnf2 _l r (Right y) = r y 598 | 599 | -- | @since 1.3.0.0 600 | instance NFData Data.Version.Version where 601 | rnf (Data.Version.Version branch tags) = rnf branch `seq` rnf tags 602 | 603 | instance NFData a => NFData [a] where rnf = rnf1 604 | 605 | -- | @since 1.4.3.0 606 | instance NFData1 [] where 607 | liftRnf f = foldr (\x r -> f x `seq` r) () 608 | {-# INLINABLE liftRnf #-} 609 | 610 | -- | @since 1.4.0.0 611 | instance NFData a => NFData (ZipList a) where rnf = rnf1 612 | 613 | -- | @since 1.4.3.0 614 | instance NFData1 ZipList where 615 | liftRnf r = liftRnf r . getZipList 616 | 617 | -- | @since 1.4.0.0 618 | instance NFData a => NFData (Const a b) where 619 | rnf = rnf . getConst 620 | 621 | -- | @since 1.4.3.0 622 | instance NFData a => NFData1 (Const a) where 623 | liftRnf _ = rnf . getConst 624 | 625 | -- | @since 1.4.3.0 626 | instance NFData2 Const where 627 | liftRnf2 r _ = r . getConst 628 | 629 | -- We should use MIN_VERSION array(0,5,1,1) but that's not possible. 630 | -- There isn't an underscore to not break C preprocessor 631 | instance (NFData a, NFData b) => NFData (Array a b) where 632 | rnf x = rnf (GHC.Arr.bounds x, GHC.Arr.elems x) 633 | 634 | -- | @since 1.4.3.0 635 | instance (NFData a) => NFData1 (Array a) where 636 | liftRnf r x = rnf (GHC.Arr.bounds x) `seq` liftRnf r (GHC.Arr.elems x) 637 | 638 | -- | @since 1.4.3.0 639 | instance NFData2 Array where 640 | liftRnf2 r r' x = 641 | liftRnf2 r r (GHC.Arr.bounds x) `seq` liftRnf r' (GHC.Arr.elems x) 642 | 643 | -- | @since 1.4.0.0 644 | instance NFData a => NFData (Down a) where rnf = rnf1 645 | 646 | -- | @since 1.4.3.0 647 | instance NFData1 Down where 648 | liftRnf r (Down x) = r x 649 | 650 | -- | @since 1.4.0.0 651 | instance NFData a => NFData (Dual a) where rnf = rnf1 652 | 653 | -- | @since 1.4.3.0 654 | instance NFData1 Dual where 655 | liftRnf r (Dual x) = r x 656 | 657 | -- | @since 1.4.0.0 658 | instance NFData a => NFData (Mon.First a) where rnf = rnf1 659 | 660 | -- | @since 1.4.3.0 661 | instance NFData1 Mon.First where 662 | liftRnf r (Mon.First x) = liftRnf r x 663 | 664 | -- | @since 1.4.0.0 665 | instance NFData a => NFData (Mon.Last a) where rnf = rnf1 666 | 667 | -- | @since 1.4.3.0 668 | instance NFData1 Mon.Last where 669 | liftRnf r (Mon.Last x) = liftRnf r x 670 | 671 | -- | @since 1.4.0.0 672 | instance NFData Any where rnf = rnf . getAny 673 | 674 | -- | @since 1.4.0.0 675 | instance NFData All where rnf = rnf . getAll 676 | 677 | -- | @since 1.4.0.0 678 | instance NFData a => NFData (Sum a) where rnf = rnf1 679 | 680 | -- | @since 1.4.3.0 681 | instance NFData1 Sum where 682 | liftRnf r (Sum x) = r x 683 | 684 | -- | @since 1.4.0.0 685 | instance NFData a => NFData (Product a) where rnf = rnf1 686 | 687 | -- | @since 1.4.3.0 688 | instance NFData1 Product where 689 | liftRnf r (Product x) = r x 690 | 691 | -- | @since 1.4.0.0 692 | instance NFData (StableName a) where 693 | rnf = rwhnf -- assumes `data StableName a = StableName (StableName# a)` 694 | 695 | -- | @since 1.4.3.0 696 | instance NFData1 StableName where 697 | liftRnf _ = rwhnf 698 | 699 | -- | @since 1.4.0.0 700 | instance NFData ThreadId where 701 | rnf = rwhnf -- assumes `data ThreadId = ThreadId ThreadId#` 702 | 703 | -- | @since 1.4.0.0 704 | instance NFData Unique where 705 | rnf = rwhnf -- assumes `newtype Unique = Unique Integer` 706 | 707 | -- | __NOTE__: Prior to @deepseq-1.4.4.0@ this instance was only defined for @base-4.8.0.0@ and later. 708 | -- 709 | -- @since 1.4.0.0 710 | instance NFData TypeRep where 711 | rnf tyrep = rnfTypeRep tyrep 712 | 713 | -- | __NOTE__: Prior to @deepseq-1.4.4.0@ this instance was only defined for @base-4.8.0.0@ and later. 714 | -- 715 | -- @since 1.4.0.0 716 | instance NFData TyCon where 717 | rnf tycon = rnfTyCon tycon 718 | 719 | -- | @since 1.4.8.0 720 | instance NFData (Reflection.TypeRep a) where 721 | rnf tr = Reflection.rnfTypeRep tr 722 | 723 | -- | @since 1.4.8.0 724 | instance NFData Reflection.Module where 725 | rnf modul = Reflection.rnfModule modul 726 | 727 | -- | __NOTE__: Only strict in the reference and not the referenced value. 728 | -- 729 | -- @since 1.4.2.0 730 | instance NFData (IORef a) where 731 | rnf = rwhnf 732 | 733 | -- | @since 1.4.3.0 734 | instance NFData1 IORef where 735 | liftRnf _ = rwhnf 736 | 737 | -- | __NOTE__: Only strict in the reference and not the referenced value. 738 | -- 739 | -- @since 1.4.2.0 740 | instance NFData (STRef s a) where 741 | rnf = rwhnf 742 | 743 | -- | @since 1.4.3.0 744 | instance NFData1 (STRef s) where 745 | liftRnf _ = rwhnf 746 | 747 | -- | @since 1.4.3.0 748 | instance NFData2 STRef where 749 | liftRnf2 _ _ = rwhnf 750 | 751 | -- | __NOTE__: Only strict in the reference and not the referenced value. 752 | -- 753 | -- @since 1.4.2.0 754 | instance NFData (MVar a) where 755 | rnf = rwhnf 756 | 757 | -- | @since 1.4.3.0 758 | instance NFData1 MVar where 759 | liftRnf _ = rwhnf 760 | 761 | ---------------------------------------------------------------------------- 762 | -- GHC Specifics 763 | 764 | -- | @since 1.4.0.0 765 | instance NFData Fingerprint where 766 | rnf (Fingerprint _ _) = () 767 | 768 | ---------------------------------------------------------------------------- 769 | -- Foreign.Ptr 770 | 771 | -- | @since 1.4.2.0 772 | instance NFData (Ptr a) where 773 | rnf = rwhnf 774 | 775 | -- | @since 1.4.3.0 776 | instance NFData1 Ptr where 777 | liftRnf _ = rwhnf 778 | 779 | -- | @since 1.4.2.0 780 | instance NFData (FunPtr a) where 781 | rnf = rwhnf 782 | 783 | -- | @since 1.4.3.0 784 | instance NFData1 FunPtr where 785 | liftRnf _ = rwhnf 786 | 787 | ---------------------------------------------------------------------------- 788 | -- Foreign.C.Types 789 | 790 | -- | @since 1.4.0.0 791 | instance NFData CChar where rnf = rwhnf 792 | 793 | -- | @since 1.4.0.0 794 | instance NFData CSChar where rnf = rwhnf 795 | 796 | -- | @since 1.4.0.0 797 | instance NFData CUChar where rnf = rwhnf 798 | 799 | -- | @since 1.4.0.0 800 | instance NFData CShort where rnf = rwhnf 801 | 802 | -- | @since 1.4.0.0 803 | instance NFData CUShort where rnf = rwhnf 804 | 805 | -- | @since 1.4.0.0 806 | instance NFData CInt where rnf = rwhnf 807 | 808 | -- | @since 1.4.0.0 809 | instance NFData CUInt where rnf = rwhnf 810 | 811 | -- | @since 1.4.0.0 812 | instance NFData CLong where rnf = rwhnf 813 | 814 | -- | @since 1.4.0.0 815 | instance NFData CULong where rnf = rwhnf 816 | 817 | -- | @since 1.4.0.0 818 | instance NFData CPtrdiff where rnf = rwhnf 819 | 820 | -- | @since 1.4.0.0 821 | instance NFData CSize where rnf = rwhnf 822 | 823 | -- | @since 1.4.0.0 824 | instance NFData CWchar where rnf = rwhnf 825 | 826 | -- | @since 1.4.0.0 827 | instance NFData CSigAtomic where rnf = rwhnf 828 | 829 | -- | @since 1.4.0.0 830 | instance NFData CLLong where rnf = rwhnf 831 | 832 | -- | @since 1.4.0.0 833 | instance NFData CULLong where rnf = rwhnf 834 | 835 | -- | @since 1.4.0.0 836 | instance NFData CIntPtr where rnf = rwhnf 837 | 838 | -- | @since 1.4.0.0 839 | instance NFData CUIntPtr where rnf = rwhnf 840 | 841 | -- | @since 1.4.0.0 842 | instance NFData CIntMax where rnf = rwhnf 843 | 844 | -- | @since 1.4.0.0 845 | instance NFData CUIntMax where rnf = rwhnf 846 | 847 | -- | @since 1.4.0.0 848 | instance NFData CClock where rnf = rwhnf 849 | 850 | -- | @since 1.4.0.0 851 | instance NFData CTime where rnf = rwhnf 852 | 853 | -- | @since 1.4.0.0 854 | instance NFData CUSeconds where rnf = rwhnf 855 | 856 | -- | @since 1.4.0.0 857 | instance NFData CSUSeconds where rnf = rwhnf 858 | 859 | -- | @since 1.4.0.0 860 | instance NFData CFloat where rnf = rwhnf 861 | 862 | -- | @since 1.4.0.0 863 | instance NFData CDouble where rnf = rwhnf 864 | 865 | -- NOTE: The types `CFile`, `CFPos`, and `CJmpBuf` below are not 866 | -- newtype wrappers rather defined as field-less single-constructor 867 | -- types. 868 | 869 | -- | @since 1.4.0.0 870 | instance NFData CFile where rnf = rwhnf 871 | 872 | -- | @since 1.4.0.0 873 | instance NFData CFpos where rnf = rwhnf 874 | 875 | -- | @since 1.4.0.0 876 | instance NFData CJmpBuf where rnf = rwhnf 877 | 878 | -- | @since 1.4.3.0 879 | instance NFData CBool where rnf = rwhnf 880 | 881 | ---------------------------------------------------------------------------- 882 | -- System.Exit 883 | 884 | -- | @since 1.4.2.0 885 | instance NFData ExitCode where 886 | rnf (ExitFailure n) = rnf n 887 | rnf ExitSuccess = () 888 | 889 | ---------------------------------------------------------------------------- 890 | -- instances previously provided by semigroups package 891 | 892 | -- | @since 1.4.2.0 893 | instance NFData a => NFData (NonEmpty a) where rnf = rnf1 894 | 895 | -- | @since 1.4.3.0 896 | instance NFData1 NonEmpty where 897 | liftRnf r (x :| xs) = r x `seq` liftRnf r xs 898 | 899 | -- | @since 1.4.2.0 900 | instance NFData a => NFData (Min a) where rnf = rnf1 901 | 902 | -- | @since 1.4.3.0 903 | instance NFData1 Min where 904 | liftRnf r (Min a) = r a 905 | 906 | -- | @since 1.4.2.0 907 | instance NFData a => NFData (Max a) where rnf = rnf1 908 | 909 | -- | @since 1.4.3.0 910 | instance NFData1 Max where 911 | liftRnf r (Max a) = r a 912 | 913 | -- | @since 1.4.2.0 914 | instance (NFData a, NFData b) => NFData (Arg a b) where rnf = rnf2 915 | 916 | -- | @since 1.4.3.0 917 | instance (NFData a) => NFData1 (Arg a) where liftRnf = liftRnf2 rnf 918 | 919 | -- | @since 1.4.3.0 920 | instance NFData2 Arg where 921 | liftRnf2 r r' (Arg a b) = r a `seq` r' b `seq` () 922 | 923 | -- | @since 1.4.2.0 924 | instance NFData a => NFData (Semi.First a) where rnf = rnf1 925 | 926 | -- | @since 1.4.3.0 927 | instance NFData1 Semi.First where 928 | liftRnf r (Semi.First a) = r a 929 | 930 | -- | @since 1.4.2.0 931 | instance NFData a => NFData (Semi.Last a) where rnf = rnf1 932 | 933 | -- | @since 1.4.3.0 934 | instance NFData1 Semi.Last where 935 | liftRnf r (Semi.Last a) = r a 936 | 937 | -- | @since 1.4.2.0 938 | instance NFData m => NFData (WrappedMonoid m) where rnf = rnf1 939 | 940 | -- | @since 1.4.3.0 941 | instance NFData1 WrappedMonoid where 942 | liftRnf r (WrapMonoid a) = r a 943 | 944 | #if __GLASGOW_HASKELL__ < 901 945 | -- |@since 1.4.2.0 946 | instance NFData a => NFData (Option a) where rnf = rnf1 947 | -- |@since 1.4.3.0 948 | instance NFData1 Option where 949 | liftRnf r (Option a) = liftRnf r a 950 | #endif 951 | 952 | ---------------------------------------------------------------------------- 953 | -- GHC.Stack 954 | 955 | -- | @since 1.4.2.0 956 | instance NFData SrcLoc where 957 | rnf (SrcLoc a b c d e f g) = 958 | rnf a `seq` rnf b `seq` rnf c `seq` rnf d `seq` rnf e `seq` rnf f `seq` rnf g 959 | 960 | -- | @since 1.4.2.0 961 | instance NFData CallStack where 962 | rnf EmptyCallStack = () 963 | rnf (PushCallStack a b c) = rnf a `seq` rnf b `seq` rnf c 964 | rnf (FreezeCallStack a) = rnf a 965 | 966 | ---------------------------------------------------------------------------- 967 | -- Tuples 968 | 969 | #ifdef MIN_VERSION_ghc_prim 970 | #if MIN_VERSION_ghc_prim(0,7,0) 971 | -- |@since 1.4.6.0 972 | instance NFData a => NFData (Solo a) where 973 | #if MIN_VERSION_ghc_prim(0,10,0) 974 | rnf (MkSolo a) = rnf a 975 | #else 976 | rnf (Solo a) = rnf a 977 | #endif 978 | -- |@since 1.4.6.0 979 | instance NFData1 Solo where 980 | #if MIN_VERSION_ghc_prim(0,10,0) 981 | liftRnf r (MkSolo a) = r a 982 | #else 983 | liftRnf r (Solo a) = r a 984 | #endif 985 | #endif 986 | #endif 987 | 988 | instance (NFData a, NFData b) => NFData (a, b) where rnf = rnf2 989 | 990 | -- | @since 1.4.3.0 991 | instance (NFData a) => NFData1 ((,) a) where liftRnf = liftRnf2 rnf 992 | 993 | -- | @since 1.4.3.0 994 | instance NFData2 (,) where 995 | liftRnf2 r r' (x, y) = r x `seq` r' y 996 | 997 | -- Code below is generated, see generate-nfdata-tuple.hs 998 | instance 999 | (NFData a1, NFData a2, NFData a3) => 1000 | NFData (a1, a2, a3) 1001 | where 1002 | rnf = rnf2 1003 | 1004 | -- | @since 1.4.3.0 1005 | instance 1006 | (NFData a1, NFData a2) => 1007 | NFData1 ((,,) a1 a2) 1008 | where 1009 | liftRnf = liftRnf2 rnf 1010 | 1011 | -- | @since 1.4.3.0 1012 | instance 1013 | (NFData a1) => 1014 | NFData2 ((,,) a1) 1015 | where 1016 | liftRnf2 r r' (x1, x2, x3) = 1017 | rnf x1 `seq` r x2 `seq` r' x3 1018 | 1019 | instance 1020 | (NFData a1, NFData a2, NFData a3, NFData a4) => 1021 | NFData (a1, a2, a3, a4) 1022 | where 1023 | rnf = rnf2 1024 | 1025 | -- | @since 1.4.3.0 1026 | instance 1027 | (NFData a1, NFData a2, NFData a3) => 1028 | NFData1 ((,,,) a1 a2 a3) 1029 | where 1030 | liftRnf = liftRnf2 rnf 1031 | 1032 | -- | @since 1.4.3.0 1033 | instance 1034 | (NFData a1, NFData a2) => 1035 | NFData2 ((,,,) a1 a2) 1036 | where 1037 | liftRnf2 r r' (x1, x2, x3, x4) = 1038 | rnf x1 `seq` rnf x2 `seq` r x3 `seq` r' x4 1039 | 1040 | instance 1041 | (NFData a1, NFData a2, NFData a3, NFData a4, NFData a5) => 1042 | NFData (a1, a2, a3, a4, a5) 1043 | where 1044 | rnf = rnf2 1045 | 1046 | -- | @since 1.4.3.0 1047 | instance 1048 | (NFData a1, NFData a2, NFData a3, NFData a4) => 1049 | NFData1 ((,,,,) a1 a2 a3 a4) 1050 | where 1051 | liftRnf = liftRnf2 rnf 1052 | 1053 | -- | @since 1.4.3.0 1054 | instance 1055 | (NFData a1, NFData a2, NFData a3) => 1056 | NFData2 ((,,,,) a1 a2 a3) 1057 | where 1058 | liftRnf2 r r' (x1, x2, x3, x4, x5) = 1059 | rnf x1 `seq` rnf x2 `seq` rnf x3 `seq` r x4 `seq` r' x5 1060 | 1061 | instance 1062 | (NFData a1, NFData a2, NFData a3, NFData a4, NFData a5, NFData a6) => 1063 | NFData (a1, a2, a3, a4, a5, a6) 1064 | where 1065 | rnf = rnf2 1066 | 1067 | -- | @since 1.4.3.0 1068 | instance 1069 | (NFData a1, NFData a2, NFData a3, NFData a4, NFData a5) => 1070 | NFData1 ((,,,,,) a1 a2 a3 a4 a5) 1071 | where 1072 | liftRnf = liftRnf2 rnf 1073 | 1074 | -- | @since 1.4.3.0 1075 | instance 1076 | (NFData a1, NFData a2, NFData a3, NFData a4) => 1077 | NFData2 ((,,,,,) a1 a2 a3 a4) 1078 | where 1079 | liftRnf2 r r' (x1, x2, x3, x4, x5, x6) = 1080 | rnf x1 `seq` rnf x2 `seq` rnf x3 `seq` rnf x4 `seq` r x5 `seq` r' x6 1081 | 1082 | instance 1083 | (NFData a1, NFData a2, NFData a3, NFData a4, NFData a5, NFData a6, NFData a7) => 1084 | NFData (a1, a2, a3, a4, a5, a6, a7) 1085 | where 1086 | rnf = rnf2 1087 | 1088 | -- | @since 1.4.3.0 1089 | instance 1090 | (NFData a1, NFData a2, NFData a3, NFData a4, NFData a5, NFData a6) => 1091 | NFData1 ((,,,,,,) a1 a2 a3 a4 a5 a6) 1092 | where 1093 | liftRnf = liftRnf2 rnf 1094 | 1095 | -- | @since 1.4.3.0 1096 | instance 1097 | (NFData a1, NFData a2, NFData a3, NFData a4, NFData a5) => 1098 | NFData2 ((,,,,,,) a1 a2 a3 a4 a5) 1099 | where 1100 | liftRnf2 r r' (x1, x2, x3, x4, x5, x6, x7) = 1101 | rnf x1 `seq` rnf x2 `seq` rnf x3 `seq` rnf x4 `seq` rnf x5 `seq` r x6 `seq` r' x7 1102 | 1103 | instance 1104 | (NFData a1, NFData a2, NFData a3, NFData a4, NFData a5, NFData a6, NFData a7, NFData a8) => 1105 | NFData (a1, a2, a3, a4, a5, a6, a7, a8) 1106 | where 1107 | rnf = rnf2 1108 | 1109 | -- | @since 1.4.3.0 1110 | instance 1111 | (NFData a1, NFData a2, NFData a3, NFData a4, NFData a5, NFData a6, NFData a7) => 1112 | NFData1 ((,,,,,,,) a1 a2 a3 a4 a5 a6 a7) 1113 | where 1114 | liftRnf = liftRnf2 rnf 1115 | 1116 | -- | @since 1.4.3.0 1117 | instance 1118 | (NFData a1, NFData a2, NFData a3, NFData a4, NFData a5, NFData a6) => 1119 | NFData2 ((,,,,,,,) a1 a2 a3 a4 a5 a6) 1120 | where 1121 | liftRnf2 r r' (x1, x2, x3, x4, x5, x6, x7, x8) = 1122 | rnf x1 `seq` rnf x2 `seq` rnf x3 `seq` rnf x4 `seq` rnf x5 `seq` rnf x6 `seq` r x7 `seq` r' x8 1123 | 1124 | instance 1125 | (NFData a1, NFData a2, NFData a3, NFData a4, NFData a5, NFData a6, NFData a7, NFData a8, NFData a9) => 1126 | NFData (a1, a2, a3, a4, a5, a6, a7, a8, a9) 1127 | where 1128 | rnf = rnf2 1129 | 1130 | -- | @since 1.4.3.0 1131 | instance 1132 | (NFData a1, NFData a2, NFData a3, NFData a4, NFData a5, NFData a6, NFData a7, NFData a8) => 1133 | NFData1 ((,,,,,,,,) a1 a2 a3 a4 a5 a6 a7 a8) 1134 | where 1135 | liftRnf = liftRnf2 rnf 1136 | 1137 | -- | @since 1.4.3.0 1138 | instance 1139 | (NFData a1, NFData a2, NFData a3, NFData a4, NFData a5, NFData a6, NFData a7) => 1140 | NFData2 ((,,,,,,,,) a1 a2 a3 a4 a5 a6 a7) 1141 | where 1142 | liftRnf2 r r' (x1, x2, x3, x4, x5, x6, x7, x8, x9) = 1143 | rnf x1 `seq` rnf x2 `seq` rnf x3 `seq` rnf x4 `seq` rnf x5 `seq` rnf x6 `seq` rnf x7 `seq` r x8 `seq` r' x9 1144 | 1145 | ---------------------------------------------------------------------------- 1146 | -- ByteArray 1147 | 1148 | #if MIN_VERSION_base(4,17,0) 1149 | -- |@since 1.4.7.0 1150 | instance NFData ByteArray where 1151 | rnf (ByteArray _) = () 1152 | 1153 | -- |@since 1.4.8.0 1154 | instance NFData (MutableByteArray s) where 1155 | rnf (MutableByteArray _) = () 1156 | #endif 1157 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This library (deepseq) is derived from code from the GHC project which 2 | is largely (c) The University of Glasgow, and distributable under a 3 | BSD-style license (see below). 4 | 5 | ----------------------------------------------------------------------------- 6 | 7 | The Glasgow Haskell Compiler License 8 | 9 | Copyright 2001-2009, The University Court of the University of Glasgow. 10 | All rights reserved. 11 | 12 | Redistribution and use in source and binary forms, with or without 13 | modification, are permitted provided that the following conditions are met: 14 | 15 | - Redistributions of source code must retain the above copyright notice, 16 | this list of conditions and the following disclaimer. 17 | 18 | - Redistributions in binary form must reproduce the above copyright notice, 19 | this list of conditions and the following disclaimer in the documentation 20 | and/or other materials provided with the distribution. 21 | 22 | - Neither name of the University nor the names of its contributors may be 23 | used to endorse or promote products derived from this software without 24 | specific prior written permission. 25 | 26 | THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY COURT OF THE UNIVERSITY OF 27 | GLASGOW AND THE CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 28 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 29 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 30 | UNIVERSITY COURT OF THE UNIVERSITY OF GLASGOW OR THE CONTRIBUTORS BE LIABLE 31 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 33 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 34 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36 | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 37 | DAMAGE. 38 | 39 | ----------------------------------------------------------------------------- 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | The `deepseq` Package [![Hackage](https://img.shields.io/hackage/v/deepseq.svg)](https://hackage.haskell.org/package/deepseq) [![ci](https://github.com/haskell/deepseq/actions/workflows/ci.yml/badge.svg)](https://github.com/haskell/deepseq/actions/workflows/ci.yml) 2 | ===================== 3 | 4 | See [`deepseq` on Hackage](http://hackage.haskell.org/package/deepseq) for more information. 5 | -------------------------------------------------------------------------------- /Setup.hs: -------------------------------------------------------------------------------- 1 | module Main (main) where 2 | 3 | import Distribution.Simple 4 | 5 | main :: IO () 6 | main = defaultMain 7 | -------------------------------------------------------------------------------- /changelog.md: -------------------------------------------------------------------------------- 1 | # Changelog for [`deepseq` package](http://hackage.haskell.org/package/deepseq) 2 | 3 | ## Upcoming 4 | 5 | 6 | 7 | ## 1.5.1.0 8 | 9 | * Add Unit monoid with `seq` 10 | ([#18](https://github.com/haskell/deepseq/issues/18), [#105](https://github.com/haskell/deepseq/issues/105)) 11 | * Drop the dependency on `array` 12 | ([#102](https://github.com/haskell/deepseq/issues/102), [#107](https://github.com/haskell/deepseq/issues/107)) 13 | 14 | ## 1.5.0.0 15 | 16 | * Add quantified superclasses to NFData(1,2) 17 | ([#88](https://github.com/haskell/deepseq/issues/88)) 18 | * Alter superclasses for Data.Functor.{Sum, Product} 19 | ([#95])(https://github.com/haskell/deepseq/pull/95) 20 | * Drop support for GHC < 8.6 21 | ([#94](https://github.com/haskell/deepseq/pull/94)) 22 | * List fusion in `instance NFData [a]` reduces allocations 23 | ([#99](https://github.com/haskell/deepseq/pull/99)) 24 | 25 | ## 1.4.8.1 26 | 27 | * Adapt the rename of the Solo constructor to MkSolo 28 | ([#87](https://github.com/haskell/deepseq/pull/87)) 29 | * Add instances for the indexed `TypeRep`, along with `Module`. 30 | ([#83](https://github.com/haskell/deepseq/pull/83)) 31 | 32 | ## 1.4.8.0 33 | 34 | * Add `NFData` instance for `MutableByteArray` 35 | ([#84](https://github.com/haskell/deepseq/pull/84)) 36 | * Change RnfArgs to be a data family 37 | ([#85](https://github.com/haskell/deepseq/pull/85)) 38 | 39 | ## 1.4.7.0 40 | 41 | * Add instances for `Solo` (GHC-9) 42 | ([#69](https://github.com/haskell/deepseq/pull/69)) 43 | * Add once again `infixr 0 deepseq` 44 | ([#56](https://github.com/haskell/deepseq/pull/56), [#74](https://github.com/haskell/deepseq/issues/74)) 45 | * Add `NFData` instance for `ByteArray` 46 | ([#65](https://github.com/haskell/deepseq/pull/65)) 47 | * Drop support for GHC 7 to simplify CPP 48 | ([#75](https://github.com/haskell/deepseq/pull/75)) 49 | 50 | ## 1.4.6.1 51 | 52 | * Revert `infixr 0 deepseq`; this does not appear in the version of `deepseq` pinned to GHC 9.2.1 53 | 54 | ## 1.4.6.0 55 | 56 | * Bundled with GHC 9.2.1 57 | * Remove instances for Data.Semigroup.Option for GHC >= 9.2 58 | ([#62](https://github.com/haskell/deepseq/pull/62)) 59 | * Set the `infixr 0 deepseq` to be consistent with `seq` 60 | ([#56](https://github.com/haskell/deepseq/pull/56)) 61 | 62 | ## 1.4.5.0 63 | 64 | * Add `GNFData` for URec 65 | This will enable deriving NFData instances for unboxed types 66 | 67 | ## 1.4.4.0 *Sep 2018* 68 | 69 | * Bundled with GHC 8.6.1 70 | 71 | * Add `NFData` instance for `MaskingState` 72 | ([#38](https://github.com/haskell/deepseq/pull/38)) 73 | 74 | * Define the `NFData` instances for `TypeRep` and `TyCon` on all supported 75 | versions of `base`, not just 4.8 and later 76 | ([#40](https://github.com/haskell/deepseq/pull/40)) 77 | 78 | ## 1.4.3.0 *Apr 2017* 79 | 80 | * Bundled with GHC 8.2.1 81 | 82 | * Drop support for GHC 7.0 & GHC 7.2 83 | 84 | * Changed strictness behavior of generic `NFData` instances for 85 | constructor-less data types. Before, a generic `rnf` 86 | implementation would always `error` on a data type with no 87 | constructors. Now, it will force the argument, so if the argument 88 | is a diverging computation, a generic `rnf` implementation will 89 | actually trigger the diverging computation. 90 | ([#19](https://github.com/haskell/deepseq/issues/19)) 91 | 92 | * Add new `rwhnf` function defined as `rwhnf !_ = ()` 93 | ([#3](https://github.com/haskell/deepseq/issues/3)) 94 | 95 | * Add `(<$!!>) :: (Monad m, NFData b) => (a -> b) -> m a -> m b` 96 | ([#13](https://github.com/haskell/deepseq/issues/13)) 97 | 98 | * Add `NFData1` and `NFData2` type classes 99 | ([#8](https://github.com/haskell/deepseq/issues/8)) 100 | 101 | * Add `NFData` instance for `Down` for `base` versions prior to 102 | `base-4.6.0` which didn't yet export it via `Data.Ord` 103 | ([#28](https://github.com/haskell/deepseq/pull/28)) 104 | 105 | * Add `NFData` instance for `Foreign.C.Types.CBool` 106 | ([#33](https://github.com/haskell/deepseq/pull/33)) 107 | 108 | * Add `NFData` instance for `Ordering` 109 | ([#25](https://github.com/haskell/deepseq/pull/25)) 110 | 111 | * Add `NFData1` and `NFData` instances for `Data.Functor.{Compose,Sum,Product}` 112 | ([#30](https://github.com/haskell/deepseq/pull/30)) 113 | 114 | * Add `NFData`, `NFData1`, and `NFData2` instances for `(:~:)` and `(:~~:)` 115 | from `Data.Type.Equality` 116 | ([#31](https://github.com/haskell/deepseq/issues/31)) 117 | 118 | ## 1.4.2.0 *Apr 2016* 119 | 120 | * Bundled with GHC 8.0.1 121 | 122 | * New instances for types provided by `semigroups` prior to 123 | `base-4.9` (i.e. `NonEmpty`, `Min`, `Max`, `Arg`, 124 | `Semigroup.First`, `Semigroup.Last`, `WrappedMonoid`, and 125 | `Option`) ([#11](https://github.com/haskell/deepseq/issues/11)) 126 | 127 | * New instances for `Ptr` and `FunPtr` 128 | ([#10](https://github.com/haskell/deepseq/pull/10)) 129 | 130 | * New instances for `IORef`, `STRef`, and `MVar` 131 | ([#6](https://github.com/haskell/deepseq/issues/6)) 132 | 133 | * New instance for `ExitCode` 134 | ([#4](https://github.com/haskell/deepseq/issues/4)) 135 | 136 | * New instances for `CallStack` and `SrcLoc` 137 | 138 | * Make `NFData (Proxy a)` instance poly-kinded 139 | 140 | ## 1.4.1.2 *Aug 2015* 141 | 142 | * Avoid the broken combination of GHC-7.2 with `array>=0.4` 143 | ([#7](https://github.com/haskell/deepseq/pull/7)) 144 | 145 | ## 1.4.1.1 *Mar 2015* 146 | 147 | * Bundled with GHC 7.10.1 148 | * Drop redundant `ghc-prim` dependency 149 | 150 | ## 1.4.1.0 *Mar 2015* 151 | 152 | * Drop redundant constraints from a few `NFData` instances (if 153 | possible for a given `base` version) 154 | 155 | ## 1.4.0.0 *Dec 2014* 156 | 157 | * Switch to Generics based `DefaultSignature` `rnf` method 158 | implementation (based on code from `deepseq-generics`) 159 | 160 | **Compatibility Note**: if you need the exact default-method 161 | semantics of `deepseq` prior to 1.4, replace occurences of 162 | 163 | instance NFData XYZ 164 | 165 | by 166 | 167 | instance NFData XYZ where rnf x = seq x () 168 | 169 | * New `NFData` instances for `base` types: 170 | 171 | - `Control.Applicative.Const` 172 | - `Control.Applicative.ZipList` 173 | - `Control.Concurrent.ThreadId` 174 | - `Data.Functor.Identity.Identity` 175 | - `Data.Monoid.{Dual,First,Last,Any,All,Sum,Product}` 176 | - `Data.Ord.Down` 177 | - `Data.Proxy.Proxy` 178 | - `Data.Typeable.Internal.TyCon` 179 | - `Data.Typeable.Internal.TypeRep` 180 | - `Data.Unique.Unique` 181 | - `Data.Void.Void` 182 | - `GHC.Fingerprint.Type.Fingerprint` 183 | - `Numeric.Natural.Natural` 184 | - `System.Mem.StableName.StableName` 185 | - `Foreign.C.Types.C*` 186 | 187 | ## 1.3.0.2 *Nov 2013* 188 | 189 | * Bundled with GHC 7.8.1 190 | * Update package description to Cabal 1.10 format 191 | * Add support for GHC 7.8 192 | * Drop support for GHCs older than GHC 7.0.1 193 | * Add `/since: .../` annotations to Haddock comments 194 | * Add changelog 195 | 196 | ## 1.3.0.1 *Sep 2012* 197 | 198 | * No changes 199 | 200 | ## 1.3.0.0 *Feb 2012* 201 | 202 | * Add instances for `Fixed`, `a->b` and `Version` 203 | 204 | ## 1.2.0.1 *Sep 2011* 205 | 206 | * Disable SafeHaskell for GHC 7.2 207 | 208 | ## 1.2.0.0 *Sep 2011* 209 | 210 | * New function `force` 211 | * New operator `$!!` 212 | * Add SafeHaskell support 213 | * Dropped dependency on containers 214 | 215 | ## 1.1.0.2 *Nov 2010* 216 | 217 | * Improve Haddock documentation 218 | 219 | ## 1.1.0.1 *Oct 2010* 220 | 221 | * Enable support for containers-0.4.x 222 | 223 | ## 1.1.0.0 *Nov 2009* 224 | 225 | * Major rewrite 226 | 227 | ## 1.0.0.0 *Nov 2009* 228 | 229 | * Initial release 230 | -------------------------------------------------------------------------------- /deepseq.cabal: -------------------------------------------------------------------------------- 1 | cabal-version: 1.12 2 | name: deepseq 3 | version: 1.5.1.0 4 | -- NOTE: Don't forget to update ./changelog.md 5 | 6 | license: BSD3 7 | license-file: LICENSE 8 | maintainer: libraries@haskell.org 9 | bug-reports: https://github.com/haskell/deepseq/issues 10 | synopsis: Deep evaluation of data structures 11 | category: Control 12 | description: 13 | This package provides methods for fully evaluating data structures 14 | (\"deep evaluation\"). Deep evaluation is often used for adding 15 | strictness to a program, e.g. in order to force pending exceptions, 16 | remove space leaks, or force lazy I/O to happen. It is also useful 17 | in parallel programs, to ensure pending work does not migrate to the 18 | wrong thread. 19 | . 20 | The primary use of this package is via the 'deepseq' function, a 21 | \"deep\" version of 'seq'. It is implemented on top of an 'NFData' 22 | typeclass (\"Normal Form Data\", data structures with no unevaluated 23 | components) which defines strategies for fully evaluating different 24 | data types. See module documentation in "Control.DeepSeq" for more 25 | details. 26 | 27 | build-type: Simple 28 | tested-with: 29 | GHC==9.10.1, 30 | GHC==9.8.2, 31 | GHC==9.6.6, 32 | GHC==9.4.8, 33 | GHC==9.2.8, 34 | GHC==9.0.2, 35 | GHC==8.10.7, 36 | GHC==8.8.4, 37 | GHC==8.6.5 38 | 39 | extra-source-files: changelog.md 40 | 41 | source-repository head 42 | type: git 43 | location: https://github.com/haskell/deepseq.git 44 | 45 | library 46 | default-language: Haskell2010 47 | other-extensions: 48 | BangPatterns 49 | CPP 50 | DefaultSignatures 51 | EmptyCase 52 | FlexibleContexts 53 | FlexibleInstances 54 | GADTs 55 | MultiParamTypeClasses 56 | PolyKinds 57 | Safe 58 | TypeOperators 59 | 60 | -- Solo lives in ghc-prim in GHC-9.0 (and maybe still in GHC-9.2) 61 | if impl(ghc >=9.0) 62 | build-depends: ghc-prim 63 | 64 | build-depends: base >= 4.12 && < 4.21 65 | ghc-options: -Wall 66 | 67 | exposed-modules: Control.DeepSeq 68 | 69 | test-suite test 70 | Default-Language: Haskell2010 71 | hs-source-dirs: tests 72 | main-is: Main.hs 73 | type: exitcode-stdio-1.0 74 | build-depends: 75 | base, 76 | deepseq, 77 | ghc-prim 78 | ghc-options: -Wall 79 | other-extensions: 80 | CPP 81 | BangPatterns 82 | DefaultSignatures 83 | DeriveDataTypeable 84 | DeriveGeneric 85 | FlexibleContexts 86 | Safe 87 | TupleSections 88 | TypeOperators 89 | -------------------------------------------------------------------------------- /generate-nfdata-tuple.hs: -------------------------------------------------------------------------------- 1 | import Data.List 2 | 3 | genNFData :: Int -> [String] 4 | genNFData n = 5 | [ "" 6 | , "instance (" ++ ctx0 ++ ") =>" 7 | , " NFData (" ++ intercalate ", " as0 ++ ") where rnf = rnf2" 8 | , "instance (" ++ ctx1 ++ ") =>" 9 | , " NFData1 ((" ++ replicate (n - 1) ',' ++ ") " ++ intercalate " " as1 ++ ") where liftRnf = liftRnf2 rnf" 10 | , "instance (" ++ ctx2 ++ ") =>" 11 | , " NFData2 ((" ++ replicate (n - 1) ',' ++ ") " ++ intercalate " " as2 ++ ") where" 12 | , " liftRnf2 r r' (" ++ intercalate "," xs ++ ") = " ++ implemantation 13 | ] 14 | where 15 | as0 = take (n - 0) $ ('a' :) . show <$> [1..] 16 | as1 = take (n - 1) $ ('a' :) . show <$> [1..] 17 | as2 = take (n - 2) $ ('a' :) . show <$> [1..] 18 | 19 | xs = take n $ ('x' : ) . show <$> [1..] 20 | 21 | ctx0 = intercalate ", " $ ("NFData " ++) <$> as0 22 | ctx1 = intercalate ", " $ ("NFData " ++) <$> as1 23 | ctx2 = intercalate ", " $ ("NFData " ++) <$> as2 24 | 25 | implemantation 26 | = intercalate " `seq` " 27 | $ zipWith (\l r -> l ++ " " ++ r) 28 | (replicate (n-2) "rnf" ++ ["r", "r'"]) 29 | xs 30 | 31 | 32 | main :: IO () 33 | main = putStr $ unlines $ concatMap (\x -> genNFData x) [3..9] 34 | -------------------------------------------------------------------------------- /tests/Main.hs: -------------------------------------------------------------------------------- 1 | -- Code reused from http://hackage.haskell.org/package/deepseq-generics 2 | {-# LANGUAGE DeriveDataTypeable #-} 3 | {-# LANGUAGE DeriveGeneric #-} 4 | {-# LANGUAGE TupleSections #-} 5 | 6 | module Main (main) where 7 | 8 | import Control.Concurrent.MVar 9 | -- IUT 10 | import Control.DeepSeq 11 | import Control.Exception 12 | import Control.Monad 13 | import Data.Bits 14 | import Data.IORef 15 | import Data.Typeable 16 | import Data.Word 17 | import GHC.Generics 18 | import System.Exit (exitFailure) 19 | import System.IO.Unsafe (unsafePerformIO) 20 | 21 | ---------------------------------------------------------------------------- 22 | -- simple hacky abstraction for testing forced evaluation via `rnf`-like functions 23 | 24 | seqStateLock :: MVar () 25 | seqStateLock = unsafePerformIO $ newMVar () 26 | {-# NOINLINE seqStateLock #-} 27 | 28 | withSeqState :: Word64 -> IO () -> IO () 29 | withSeqState expectedState act = withMVar seqStateLock $ \() -> do 30 | 0 <- resetSeqState 31 | () <- act 32 | st <- resetSeqState 33 | unless (st == expectedState) $ do 34 | putStrLn $ 35 | "withSeqState: actual seq-state (" 36 | ++ show st 37 | ++ ") doesn't match expected value (" 38 | ++ show expectedState 39 | ++ ")" 40 | exitFailure 41 | 42 | seqState :: IORef Word64 43 | seqState = unsafePerformIO $ newIORef 0 44 | {-# NOINLINE seqState #-} 45 | 46 | resetSeqState :: IO Word64 47 | resetSeqState = atomicModifyIORef' seqState (0,) 48 | 49 | -- | Set flag and raise exception is flag already set 50 | setSeqState :: Int -> IO () 51 | setSeqState i 52 | | 0 <= i && i < 64 = atomicModifyIORef' seqState go 53 | | otherwise = error "seqSeqState: flag index must be in [0..63]" 54 | where 55 | go x 56 | | testBit x i = error ("setSeqState: flag #" ++ show i ++ " already set") 57 | | otherwise = (setBit x i, ()) 58 | 59 | -- weird type whose NFData instance calls 'setSeqState' when rnf-ed 60 | data SeqSet = SeqSet !Int | SeqIgnore 61 | deriving (Show) 62 | 63 | instance NFData SeqSet where 64 | rnf (SeqSet i) = unsafePerformIO $ setSeqState i 65 | rnf (SeqIgnore) = () 66 | {-# NOINLINE rnf #-} 67 | 68 | -- | Exception to be thrown for testing 'seq'/'rnf' 69 | data RnfEx = RnfEx deriving (Eq, Show, Typeable) 70 | 71 | instance Exception RnfEx 72 | 73 | instance NFData RnfEx where rnf e = throw e 74 | 75 | assertRnfEx :: () -> IO () 76 | assertRnfEx v = handleJust isWanted (const $ return ()) $ do 77 | () <- evaluate v 78 | putStrLn "failed to trigger expected RnfEx exception" 79 | exitFailure 80 | where 81 | isWanted = guard . (== RnfEx) 82 | 83 | ---------------------------------------------------------------------------- 84 | 85 | testCase :: String -> IO a -> IO a 86 | testCase testName io = do 87 | putStrLn testName 88 | io 89 | 90 | case_1, case_2, case_3 :: IO () 91 | case_4_1, case_4_2, case_4_3, case_4_4 :: IO () 92 | case_4_1b, case_4_2b, case_4_3b, case_4_4b :: IO () 93 | 94 | newtype Case1 = Case1 Int 95 | deriving (Generic) 96 | 97 | instance NFData Case1 98 | 99 | case_1 = testCase "Case1" $ do 100 | assertRnfEx $ rnf $ (Case1 (throw RnfEx)) 101 | 102 | ---- 103 | 104 | data Case2 = Case2 Int 105 | deriving (Generic) 106 | 107 | instance NFData Case2 108 | 109 | case_2 = testCase "Case2" $ do 110 | assertRnfEx $ rnf $ (Case2 (throw RnfEx)) 111 | 112 | ---- 113 | 114 | data Case3 = Case3 RnfEx 115 | deriving (Generic) 116 | 117 | instance NFData Case3 118 | 119 | case_3 = testCase "Case3" $ do 120 | assertRnfEx $ rnf $ Case3 RnfEx 121 | 122 | ---- 123 | 124 | data Case4 a 125 | = Case4a 126 | | Case4b a a 127 | | Case4c a (Case4 a) 128 | deriving 129 | ( Generic 130 | , Generic1 131 | ) 132 | 133 | instance NFData a => NFData (Case4 a) 134 | 135 | instance NFData1 Case4 136 | 137 | case_4_1 = testCase "Case4.1" $ withSeqState 0x0 $ do 138 | evaluate $ rnf $ (Case4a :: Case4 SeqSet) 139 | 140 | case_4_2 = testCase "Case4.2" $ withSeqState 0x3 $ do 141 | evaluate $ rnf $ (Case4b (SeqSet 0) (SeqSet 1) :: Case4 SeqSet) 142 | 143 | case_4_3 = testCase "Case4.3" $ withSeqState (bit 55) $ do 144 | evaluate $ rnf $ (Case4b SeqIgnore (SeqSet 55) :: Case4 SeqSet) 145 | 146 | case_4_4 = testCase "Case4.4" $ withSeqState 0xffffffffffffffff $ do 147 | evaluate $ rnf $ (genCase 63) 148 | where 149 | genCase n 150 | | n > 1 = Case4c (SeqSet n) (genCase (n - 1)) 151 | | otherwise = Case4b (SeqSet 0) (SeqSet 1) 152 | 153 | case_4_1b = testCase "Case4.1b" $ withSeqState 0x0 $ do 154 | evaluate $ rnf1 $ (Case4a :: Case4 SeqSet) 155 | 156 | case_4_2b = testCase "Case4.2b" $ withSeqState 0x3 $ do 157 | evaluate $ rnf1 $ (Case4b (SeqSet 0) (SeqSet 1) :: Case4 SeqSet) 158 | 159 | case_4_3b = testCase "Case4.3b" $ withSeqState (bit 55) $ do 160 | evaluate $ rnf1 $ (Case4b SeqIgnore (SeqSet 55) :: Case4 SeqSet) 161 | 162 | case_4_4b = testCase "Case4.4b" $ withSeqState 0xffffffffffffffff $ do 163 | evaluate $ rnf1 $ (genCase 63) 164 | where 165 | genCase n 166 | | n > 1 = Case4c (SeqSet n) (genCase (n - 1)) 167 | | otherwise = Case4b (SeqSet 0) (SeqSet 1) 168 | 169 | ---------------------------------------------------------------------------- 170 | 171 | main :: IO () 172 | main = 173 | sequence_ 174 | [ case_1 175 | , case_2 176 | , case_3 177 | , case_4_1 178 | , case_4_2 179 | , case_4_3 180 | , case_4_4 181 | , case_4_1b 182 | , case_4_2b 183 | , case_4_3b 184 | , case_4_4b 185 | ] 186 | --------------------------------------------------------------------------------