haskell / deepseq Goto Github PK
View Code? Open in Web Editor NEWDeep evaluation of data structures
Home Page: http://hackage.haskell.org/package/deepseq
License: Other
Deep evaluation of data structures
Home Page: http://hackage.haskell.org/package/deepseq
License: Other
newtype Whnf a = Whnf a
newtype Whnf1 f a = Whnf1 (f a)
newtype Whnf2 bi a b = Whnf2 (bi a b)
instance NFData (Whnf a) where rnf (Whnf a) = a `seq` ()
instance NFData1 (Whnf1 f) where liftRnf _ (Whnf1 as) = as `seq` ()
instance NFData2 (Whnf2 bi) where liftRnf2 _ _ (Whnf2 as) = as `seq` ()
We will need a Hackage release in the next two weeks or so for GHC 9.6.1. Currently we are using 28f4d5b. A release from this commit would be greatly appreciated.
Here's an idea for a helper I wanted to document:
-- | Reduce to weak head normal form
--
-- Useful for defining 'NFData' for types for which NF=WHNF holds.
--
-- > data T = C1 | C2 | C3
-- > instance NFData T where rnf = rwhnf
rwhnf :: a -> ()
rwhnf !_ = ()
The changelog for 1.4.5.0 has:
Set infixr 0 for deepseq Makes infix use of 'deepseq' parse the same way as infix use of 'seq'
entry,
However:
% ghci-9.0.1
GHCi, version 9.0.1: https://www.haskell.org/ghc/ :? for help
Loaded GHCi configuration from /home/phadej/.ghci
Prelude> :m +Control.DeepSeq
Prelude Control.DeepSeq> :i deepseq
deepseq :: NFData a => a -> b -> b -- Defined in ‘Control.DeepSeq’
and
deepseq-1.4.5.0 % cabal repl -w ghc-8.6.5
Resolving dependencies...
Build profile: -w ghc-8.6.5 -O1
In order, the following will be built (use -v for more details):
- deepseq-1.4.5.0 (lib) (first run)
Configuring library for deepseq-1.4.5.0..
Preprocessing library for deepseq-1.4.5.0..
GHCi, version 8.6.5: http://www.haskell.org/ghc/ :? for help
Loaded GHCi configuration from /home/phadej/.ghci
[1 of 2] Compiling Control.DeepSeq ( Control/DeepSeq.hs, interpreted )
[2 of 2] Compiling Control.DeepSeq.BackDoor ( Control/DeepSeq/BackDoor.hs, interpreted )
Ok, two modules loaded.
*Control.DeepSeq> :i de
decodeFloat deepseq denominator
*Control.DeepSeq> :i deepseq
deepseq :: NFData a => a -> b -> b
-- Defined at Control/DeepSeq.hs:235:1
but for 1.4.6.0:
deepseq-1.4.6.0 % cabal repl -w ghc-8.6.5
Resolving dependencies...
Build profile: -w ghc-8.6.5 -O1
In order, the following will be built (use -v for more details):
- deepseq-1.4.6.0 (lib) (first run)
Configuring library for deepseq-1.4.6.0..
Preprocessing library for deepseq-1.4.6.0..
GHCi, version 8.6.5: http://www.haskell.org/ghc/ :? for help
Loaded GHCi configuration from /home/phadej/.ghci
[1 of 2] Compiling Control.DeepSeq ( Control/DeepSeq.hs, interpreted )
[2 of 2] Compiling Control.DeepSeq.BackDoor ( Control/DeepSeq/BackDoor.hs, interpreted )
Ok, two modules loaded.
*Control.DeepSeq> :i deepseq
deepseq :: NFData a => a -> b -> b
-- Defined at Control/DeepSeq.hs:241:1
infixr 0 `deepseq`
Configuring deepseq-1.4.2.0...
Preprocessing library for deepseq-1.4.2.0..
Building library for deepseq-1.4.2.0..
[1 of 1] Compiling Control.DeepSeq ( Control/DeepSeq.hs, .stack-work/dist/x86_64-osx/Cabal-2.0.0.0/build/Control/DeepSeq.o )
/private/var/folders/pq/xz5t60ld4v10j_tt7bd25rfhtzqwq8/T/stack92873/deepseq-1.4.2.0/Control/DeepSeq.hs:420:10: error:
• Illegal instance declaration for ‘NFData TypeRep’
(All instance types must be of the form (T t1 ... tn)
where T is not a synonym.
Use TypeSynonymInstances if you want to disable this.)
• In the instance declaration for ‘NFData TypeRep’
|
420 | instance NFData TypeRep where
| ^^^^^^^^^^^^^^
but already bundled with GHC-9.2.0-rc1.
(Also there is no changelog entry in the repository, or even a tag, which is what I was looking for).
I propose an NFData
method (by some name)
whnfIsNf :: proxy a -> Bool
whnfIsNf _ = False
Then we can have, for example,
instance NFData Integer where
whnfIsNf _ = True
instance NFData a => NFData (Set a) where
whnfIsNf _ = whnfIsNf (Proxy :: Proxy a)
rnf
| whnfIsNf (Proxy :: Proxy a)
= \ !_ -> ()
| otherwise
= ....
This can avoid a bunch of unnecessary traversals.
We are quickly approaching the final release for 9.4.1 and we do not plan to merge any further breaking changes. A prompt release would be greatly appreciated.
Control.Monad
offers <$!>
. By analogy, I believe this package should offer
(<$!!>) :: (Monad m, NFData b) => (a -> b) -> m a -> m b
f <$!!> m = m >>= \x -> return $!! f x
Current implementation of $!!
is:
deepseq :: NFData a => a -> b -> b
deepseq a b = rnf a `seq` b
($!!) :: (NFData a) => (a -> b) -> a -> b
f $!! x = x `deepseq` f x
-- f $!! x = rnf x `seq` f x
However per documentation of seq
and deepseq
the second argument may be evaluated before the first one. This means that means that f x
may be evaluated before rnf x
.
Probably this should be changed to:
($!!) :: (NFData a) => (a -> b) -> a -> b
f $!! x = let f' = rnf x `seq` f in f' x
This way f
may be evaluated before rnf x
but f' x
/f x
will be evaluated after rnf x
.
GHC 8.10.1 will ship with deepseq
based upon da0eda3. It would be great to have a release cut based on this commit in the next week.
There are (so far successful) plans back to GHC-7.4
Either officially drop older GHC support and raise the base
lower-bound, or please add CI for older GHCs too.
We can do something like
liftRnf f = foldr (\x r -> f x `seq` r) ()
This is useful when the list isn't going to be used again. In practice, this mostly occurs
For fun, here it is point free (I wouldn't use this):
liftRnf f = foldr (seq . f) ()
cc @treeowl
I notice/realise we expose some instances that are defined based on base
version despite them existing before the given base
version. This is obviously a problem as it would violate the package abstraction in a non-benign way.
If we have f :: b -> Void
and g :: a -> b
, we can get f . g :: a -> Void
. But if we do this recursively, we'll get closures of increasing size. Would it make sense to offer something like this?
compNeg :: NFData a => (b -> Void) -> (a -> b) -> a -> Void
compNeg _ _ a = a `deepseq` error "Weird NFData instance or something"
I suggested to remove the instance NFData (a -> b) because it cannot be implemented properly. I think the proposal got broad support:
https://mail.haskell.org/libraries/2016-May/026961.html
We have still to decide whether to drop the instance or replace it by an unimplementable one. The latter one would have the advantage that people see that the instance is omitted by intention. We would need a major version bump. I can setup a pull request if you like.
It's missing, and seems like there is no reason to omit it.
I have 2 datatypes for 4x4 matrix of Float:
I suppose they have to be identical, but derived core code for NFData instance turns out to be different:
-- RHS size: {terms: 5, types: 18, coercions: 0}
$fNFDataMatrix4x4f_$s$dmrnf :: Matrix4x4f -> ()
$fNFDataMatrix4x4f_$s$dmrnf =
\ (eta_X8zo :: Matrix4x4f) ->
case eta_X8zo
of _
{ Matrix4x4f dt_d8x5 dt1_d8x6 dt2_d8x7 dt3_d8x8 dt4_d8x9 dt5_d8xa
dt6_d8xb dt7_d8xc dt8_d8xd dt9_d8xe dt10_d8xf dt11_d8xg dt12_d8xh
dt13_d8xi dt14_d8xj dt15_d8xk ->
()
}
-- RHS size: {terms: 70, types: 954, coercions: 0}
$fNFDataMatrix4x4f_$s$dmrnf :: Matrix4x4f -> ()
$fNFDataMatrix4x4f_$s$dmrnf =
\ (eta_a8Bf :: Matrix4x4f) ->
case eta_a8Bf
of _
{ Matrix4x4f ww1_s8VG ww2_s8VH ww3_s8VI ww4_s8VJ ww5_s8VK ww6_s8VL
ww7_s8VM ww8_s8VN ww9_s8VO ww10_s8VP ww11_s8VQ ww12_s8VR ww13_s8VS
ww14_s8VT ww15_s8VU ww16_s8VV ->
case $w$cfrom
ww1_s8VG
ww2_s8VH
ww3_s8VI
ww4_s8VJ
ww5_s8VK
ww6_s8VL
ww7_s8VM
ww8_s8VN
ww9_s8VO
ww10_s8VP
ww11_s8VQ
ww12_s8VR
ww13_s8VS
ww14_s8VT
ww15_s8VU
ww16_s8VV
of _ { (# ww18_s8Yp, ww19_s8Yq #) ->
case ww18_s8Yp of _ { :*: ww21_s8W3 ww22_s8Wj ->
case ww21_s8W3 of _ { :*: ww24_s8W6 ww25_s8Wc ->
case ww24_s8W6 of _ { :*: ww27_s8W9 ww28_s8Wa ->
case ww25_s8Wc of _ { :*: ww30_s8Wf ww31_s8Wg ->
case ww22_s8Wj of _ { :*: ww33_s8Wm ww34_s8Ws ->
case ww33_s8Wm of _ { :*: ww36_s8Wp ww37_s8Wq ->
case ww34_s8Ws of _ { :*: ww39_s8Wv ww40_s8Ww ->
case ww27_s8W9 of _ { __DEFAULT ->
case ww28_s8Wa of _ { __DEFAULT ->
case ww30_s8Wf of _ { __DEFAULT ->
case ww31_s8Wg of _ { __DEFAULT ->
case ww36_s8Wp of _ { __DEFAULT ->
case ww37_s8Wq of _ { __DEFAULT ->
case ww39_s8Wv of _ { __DEFAULT ->
case ww40_s8Ww of _ { __DEFAULT -> $fNFDataMatrix4x4f3 ww19_s8Yq }
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
Patch on the way.
NFData for TypeRep is only implemented in newer GHC's. I suggest implementing it as rnf . show
in those older GHCs so at least it is available, even if less efficient.
See ekmett/semigroups#56 for more details
Currently, the Travis script is using a hacky setup that should probably be replaced with haskell-ci
. I've made an effort to do so on the tests-in-separate-component
branch. Because the dependencies of the test suite depend on deepseq
, we have to put the tests in a separate .cabal
file to work around haskell/cabal#5200, à la haskell/primitive#90 and ekmett/transformers-compat#33.
Alas, that branch currently is failing to build. It's always the same failure, when trying to build time
:
cabal: can't find include file HsTimeConfig.h
I don't know how to fix this, so I'm giving up for now.
I'd like to propose the following instances:
instance NFData (IORef a) where rnf x = seq x ()
instance NFData (TVar a) where rnf x = seq x ()
instance NFData (MVar a) where rnf x = seq x ()
I think forcing a mutable container should not force the contained value, since that is not really "part" of the data type, it is just referenced. The instances are nevertheless useful when working with APIs that expect NFData types, for example criterion.
This seems a bit odd, since the only change was a Read
instance.
I'm currently in a situation where I want to rnf
a value from an upstream library, but it doesn't define NFData
instances.
It does, however, define a Generic
instance. If there were NFData
instances for the data types defined in GHC.Generics
(eg U1
etc), I could write rnf . GHC.Generics.from
. Alternatively, if deepseq
exported its grnf
definition, I could similarly write grnf . GHC.Generics.from
.
Either of those would let me avoid something like an orphan instance etc. (Those can be harmless eg in exes or tests, but I try to avoid them in general.)
Are there pitfalls that would make exporting these instances/grnf
a footgun for users, or would this merely provide users more options? Thanks.
In line with base: Relax instances for Functor combinators; put superclass on Class1 to make non-breaking we should add superclasses to NFData(1,2)
class (forall a. NFData (f a)) => NFData1 f
class (forall a. NFData a => NFData1 (bi a)) => NFData2 bi
I'd like a type that can be used to wrap values for which I want WHNF = NF. This is useful for satisfying NFData constraints with criterion for example.
newtype WHNF a = WHNF a
instance NFData (WHNF a) where rnf (WHNF a) = seq a ()
Of course, this data type should be given a better name. Maybe data
instead of newtype
would also be useful for even more laziness?
Thanks in advance!
It would be great if we could get a release off of 13c1c84 to ship with GHC 9.0.1.
quoting http://permalink.gmane.org/gmane.comp.lang.haskell.libraries/24907, Henning writes
I have the type
data NonEmpty f a = NonEmpty a (f a)and want to declare an NFData instance in Haskell 98. With the
existing NFData class this is not possible because it requires a
(NFData (f a)) constraint which needs FlexibleContexts. A solution
would be an NFData1 class analogously to the classes in
transformers:Data.Functor.Classes:class NFData1 f where rnf1 :: NFData a => f a -> () instance NFData1 [] where rnf1 = rnf instance (NFData1 f) => NFData1 (NonEmpty f) where rnf1 (NonEmpty x xs) = rnf (x, rnf1 xs) instance (NFData1 f, NFData a) => NFData (NonEmpty f a) where rnf = rnf1
1.4.6.1
Revert infixr 0 deepseq; this is a breaking change and requires a major version bump
It has been discussed in #56, https://mail.haskell.org/pipermail/libraries/2020-April/030361.html
I also remember (but fail to find discussions) that this change is one where not adhering to SHOULD in PVP is justified. The major bump in deepseq
version library would (especially now) make people angry for no reason, and the change doesn't break anything, as deepseq
combinator cannot be meaningfully chained with its current infixl 9
.
While testing some packages which depend on deepseq
with GHC 8.2, I noticed that there is some breakage:
[1 of 1] Compiling Control.DeepSeq (...)
/tmp/stack4748/deepseq-1.4.2.0/Control/DeepSeq.hs:420:10: error:
• Illegal instance declaration for ‘NFData TypeRep’
(All instance types must be of the form (T t1 ... tn)
where T is not a synonym.
Use TypeSynonymInstances if you want to disable this.)
• In the instance declaration for ‘NFData TypeRep’
|
420 | instance NFData TypeRep where
| ^^^^^^^^^^^^^^
Using a CPP to conditionally include the instance should resolve the problem.
Currently, we have
instance GNFData V1 where
grnf = error "Control.DeepSeq.rnf: uninhabited type"
For old GHC, we should have
grnf x = x `pseq` error "Control.DeepSeq.rnf: uninhabited type"
For newer GHC, we should have
grnf x = case x of {}
This is a left-over issue from #6
As described in #6 (comment) by @glguy defining an instance for TVar
is complicated since we'd lose {-# LANGUAGE Safe #-}
by import TVar
which seems undesirable, given all other instances can be imported safely.
It's possible to define a reasonable NFData
instance for any Foldable
type. We can offer a suitable rnf
to help.
data Unit = Unit
instance Monoid Unit where
mempty = Unit
Unit `mappend` Unit = Unit -- strict in both arguments, unlike ()
rnfFoldable :: (Foldable f, NFData a) => f a -> ()
rnfFoldable xs = foldMap (\x -> rnf x `seq` Unit) xs `seq` ()
This is a reminder to make sure we don't forget to add new NFData
instances
rnf (Proxy :: Proxy 0)
fails with this error:
No instance for (deepseq-1.4.1.1:Control.DeepSeq.NFData (Proxy 0))
arising from a use of ‘nf’
To be aligned with change Eq1 and Ord1 instances in base-4.18
(GHC-8.6). The #88 could done at the same time. The change in base
is described in haskell/core-libraries-committee#10, AFAICT the rationale applies to deepseq
as well.
cc @Icelandjack and @Ericson2314
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.