
I propose the following (abstract) data type, functions, and instance be added to deepseq (naming amenable to bikeshedding): newtype NF a = NF a -- abstract makeNF :: NFData a => a -> NF a getNF :: NF a -> a instance NFData (NF a) where rnf x = x `seq` () NF is an abstract data type representing data which has been evaluated to normal form; the guarantee specifically is, if NF is in whnf, then it is in nf. Crucially, when we have 'NF a', we ONLY need to seq it in order to assure that it is fully evaluated. This guarantee is sufficient for a variety of cases where normal data is necessary, e.g. when transmitting data over Channels. For example, from the monad-par library 'put_' could be used in place of 'put' with this type signature. put_ :: IVar (NF a) -> (NF a) -> Par () Cheers, Edward

Sounds great, +1. On 10/02/15 10:46, Edward Z. Yang wrote:
I propose the following (abstract) data type, functions, and instance be added to deepseq (naming amenable to bikeshedding):
newtype NF a = NF a -- abstract makeNF :: NFData a => a -> NF a getNF :: NF a -> a instance NFData (NF a) where rnf x = x `seq` ()
NF is an abstract data type representing data which has been evaluated to normal form; the guarantee specifically is, if NF is in whnf, then it is in nf. Crucially, when we have 'NF a', we ONLY need to seq it in order to assure that it is fully evaluated.
This guarantee is sufficient for a variety of cases where normal data is necessary, e.g. when transmitting data over Channels. For example, from the monad-par library 'put_' could be used in place of 'put' with this type signature.
put_ :: IVar (NF a) -> (NF a) -> Par ()
Cheers, Edward _______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

On 10 February 2015 at 19:46, Edward Z. Yang
I propose the following (abstract) data type, functions, and instance be added to deepseq (naming amenable to bikeshedding):
newtype NF a = NF a -- abstract makeNF :: NFData a => a -> NF a getNF :: NF a -> a instance NFData (NF a) where rnf x = x `seq` ()
What about also adding `unsafeMakeNF :: a -> NF a` for times when you may have already made a value into normal form? Either way, +1.
NF is an abstract data type representing data which has been evaluated to normal form; the guarantee specifically is, if NF is in whnf, then it is in nf. Crucially, when we have 'NF a', we ONLY need to seq it in order to assure that it is fully evaluated.
This guarantee is sufficient for a variety of cases where normal data is necessary, e.g. when transmitting data over Channels. For example, from the monad-par library 'put_' could be used in place of 'put' with this type signature.
put_ :: IVar (NF a) -> (NF a) -> Par ()
Cheers, Edward _______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
-- Ivan Lazar Miljenovic Ivan.Miljenovic@gmail.com http://IvanMiljenovic.wordpress.com

On 2015-02-10 at 09:46:37 +0100, Edward Z. Yang wrote:
I propose the following (abstract) data type, functions, and instance be added to deepseq (naming amenable to bikeshedding):
newtype NF a = NF a -- abstract makeNF :: NFData a => a -> NF a getNF :: NF a -> a
instance NFData (NF a) where rnf x = x `seq` ()
I generally like it, so count me as +1 bikeshed-wondering though, why did you make it abstract w/ separate construct/deconstructors? as a related concept (and hoping not to derail the discussion too much), I had attempted some time ago to implement TH predicates that could infer if WHNF=NF holds: http://hackage.haskell.org/package/deepseq-th-0.1.0.4/docs/Control-DeepSeq-T... and back then I was wondering, if GHC couldn't help us out here (maybe by providing an implicit NF=WHNF class-instance -- and btw, I recently found out, Haskell 1.4 had an implicit 'Eval'-class declaring `seq`-ability) I'm not sure though if WHNF=NF can always be decided... Cheers, hvr

On Tue Feb 10 2015 at 1:41:48 PM Herbert Valerio Riedel
On 2015-02-10 at 09:46:37 +0100, Edward Z. Yang wrote:
I propose the following (abstract) data type, functions, and instance be added to deepseq (naming amenable to bikeshedding):
newtype NF a = NF a -- abstract makeNF :: NFData a => a -> NF a getNF :: NF a -> a
instance NFData (NF a) where rnf x = x `seq` ()
I generally like it, so count me as +1
bikeshed-wondering though, why did you make it abstract w/ separate construct/deconstructors?
If the real constructor was available, then someone would be free to write something like: let foo = NF $ 1 : undefined which would break the guarantees that this type is trying to provide.
as a related concept (and hoping not to derail the discussion too much), I had attempted some time ago to implement TH predicates that could infer if WHNF=NF holds:
http://hackage.haskell.org/package/deepseq-th-0.1.0.4/ docs/Control-DeepSeq-TH.html#v:typeWhnfIsNf
and back then I was wondering, if GHC couldn't help us out here (maybe by providing an implicit NF=WHNF class-instance -- and btw, I recently found out, Haskell 1.4 had an implicit 'Eval'-class declaring `seq`-ability)
I'm not sure though if WHNF=NF can always be decided...
Cheers, hvr _______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

Forgot to mention: I'm +1 on the proposal in general, though it would be
nice if these types/functions were available from a compatibility library
as well, since deepseq is now bundled with GHC and therefore difficult to
upgrade on its own.
On Tue Feb 10 2015 at 1:43:52 PM Michael Snoyman
On Tue Feb 10 2015 at 1:41:48 PM Herbert Valerio Riedel
wrote: On 2015-02-10 at 09:46:37 +0100, Edward Z. Yang wrote:
I propose the following (abstract) data type, functions, and instance be added to deepseq (naming amenable to bikeshedding):
newtype NF a = NF a -- abstract makeNF :: NFData a => a -> NF a getNF :: NF a -> a
instance NFData (NF a) where rnf x = x `seq` ()
I generally like it, so count me as +1
bikeshed-wondering though, why did you make it abstract w/ separate construct/deconstructors?
If the real constructor was available, then someone would be free to write something like:
let foo = NF $ 1 : undefined
which would break the guarantees that this type is trying to provide.
as a related concept (and hoping not to derail the discussion too much), I had attempted some time ago to implement TH predicates that could infer if WHNF=NF holds:
http://hackage.haskell.org/package/deepseq-th-0.1.0.4/docs/ Control-DeepSeq-TH.html#v:typeWhnfIsNf
and back then I was wondering, if GHC couldn't help us out here (maybe by providing an implicit NF=WHNF class-instance -- and btw, I recently found out, Haskell 1.4 had an implicit 'Eval'-class declaring `seq`-ability)
I'm not sure though if WHNF=NF can always be decided...
Cheers, hvr _______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

+1, generally. Two thoughts:
1. There are, as far as I know, two reasonable senses of NF that one
might care about. The weak sense is a guarantee that the structure has
no accessible bottoms within it that would be reached if the structure
were evaluated to normal form, along with a guarantee that it is
impossible to use it to force lazy IO. A stronger sense offers some
kind of performance guarantee, which seems much trickier to specify.
Whether something is *actually* in normal form is not observable
without using something like ticky-ticky profiling, so I don't think
we're allowed to care about that. Since I support the idea of
unsafeMakeNF, and perhaps other special NF-creation functions, I think
it's important to be clear about just what it's supposed to mean.
2. I think it makes a lot of sense to put unsafeMakeNF into a separate
Unchecked module, presumably declared unsafe for Safe Haskell.
On Tue, Feb 10, 2015 at 6:45 AM, Michael Snoyman
Forgot to mention: I'm +1 on the proposal in general, though it would be nice if these types/functions were available from a compatibility library as well, since deepseq is now bundled with GHC and therefore difficult to upgrade on its own.
On Tue Feb 10 2015 at 1:43:52 PM Michael Snoyman
wrote: On Tue Feb 10 2015 at 1:41:48 PM Herbert Valerio Riedel
wrote: On 2015-02-10 at 09:46:37 +0100, Edward Z. Yang wrote:
I propose the following (abstract) data type, functions, and instance be added to deepseq (naming amenable to bikeshedding):
newtype NF a = NF a -- abstract makeNF :: NFData a => a -> NF a getNF :: NF a -> a
instance NFData (NF a) where rnf x = x `seq` ()
I generally like it, so count me as +1
bikeshed-wondering though, why did you make it abstract w/ separate construct/deconstructors?
If the real constructor was available, then someone would be free to write something like:
let foo = NF $ 1 : undefined
which would break the guarantees that this type is trying to provide.
as a related concept (and hoping not to derail the discussion too much), I had attempted some time ago to implement TH predicates that could infer if WHNF=NF holds:
http://hackage.haskell.org/package/deepseq-th-0.1.0.4/docs/Control-DeepSeq-T...
and back then I was wondering, if GHC couldn't help us out here (maybe by providing an implicit NF=WHNF class-instance -- and btw, I recently found out, Haskell 1.4 had an implicit 'Eval'-class declaring `seq`-ability)
I'm not sure though if WHNF=NF can always be decided...
Cheers, hvr _______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

i dont think it would be unsafe relative to unsafe haskell, merely unsafe
wrt the semantical guarantees of the NF type
On Tue, Feb 10, 2015 at 12:08 PM, David Feuer
+1, generally. Two thoughts:
1. There are, as far as I know, two reasonable senses of NF that one might care about. The weak sense is a guarantee that the structure has no accessible bottoms within it that would be reached if the structure were evaluated to normal form, along with a guarantee that it is impossible to use it to force lazy IO. A stronger sense offers some kind of performance guarantee, which seems much trickier to specify. Whether something is *actually* in normal form is not observable without using something like ticky-ticky profiling, so I don't think we're allowed to care about that. Since I support the idea of unsafeMakeNF, and perhaps other special NF-creation functions, I think it's important to be clear about just what it's supposed to mean.
2. I think it makes a lot of sense to put unsafeMakeNF into a separate Unchecked module, presumably declared unsafe for Safe Haskell.
Forgot to mention: I'm +1 on the proposal in general, though it would be nice if these types/functions were available from a compatibility
On Tue, Feb 10, 2015 at 6:45 AM, Michael Snoyman
wrote: library as well, since deepseq is now bundled with GHC and therefore difficult to upgrade on its own.
On Tue Feb 10 2015 at 1:43:52 PM Michael Snoyman
wrote: On Tue Feb 10 2015 at 1:41:48 PM Herbert Valerio Riedel
wrote: On 2015-02-10 at 09:46:37 +0100, Edward Z. Yang wrote:
I propose the following (abstract) data type, functions, and instance be added to deepseq (naming amenable to bikeshedding):
newtype NF a = NF a -- abstract makeNF :: NFData a => a -> NF a getNF :: NF a -> a
instance NFData (NF a) where rnf x = x `seq` ()
I generally like it, so count me as +1
bikeshed-wondering though, why did you make it abstract w/ separate construct/deconstructors?
If the real constructor was available, then someone would be free to
write
something like:
let foo = NF $ 1 : undefined
which would break the guarantees that this type is trying to provide.
as a related concept (and hoping not to derail the discussion too
much),
I had attempted some time ago to implement TH predicates that could infer if WHNF=NF holds:
http://hackage.haskell.org/package/deepseq-th-0.1.0.4/docs/Control-DeepSeq-T...
and back then I was wondering, if GHC couldn't help us out here (maybe by providing an implicit NF=WHNF class-instance -- and btw, I recently found out, Haskell 1.4 had an implicit 'Eval'-class declaring `seq`-ability)
I'm not sure though if WHNF=NF can always be decided...
Cheers, hvr _______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

Thinking about this more, I think my first sense can be made more
precise like this:
(getNF . makeNF $ v) must be indistinguishable from (force v) within
the Haskell language, and when evaluated to WHNF they must force the
same lazy IO to be performed (if any).
I still don't know how to specify the performance expectations.
On Tue, Feb 10, 2015 at 12:08 PM, David Feuer
+1, generally. Two thoughts:
1. There are, as far as I know, two reasonable senses of NF that one might care about. The weak sense is a guarantee that the structure has no accessible bottoms within it that would be reached if the structure were evaluated to normal form, along with a guarantee that it is impossible to use it to force lazy IO. A stronger sense offers some kind of performance guarantee, which seems much trickier to specify. Whether something is *actually* in normal form is not observable without using something like ticky-ticky profiling, so I don't think we're allowed to care about that. Since I support the idea of unsafeMakeNF, and perhaps other special NF-creation functions, I think it's important to be clear about just what it's supposed to mean.
2. I think it makes a lot of sense to put unsafeMakeNF into a separate Unchecked module, presumably declared unsafe for Safe Haskell.
On Tue, Feb 10, 2015 at 6:45 AM, Michael Snoyman
wrote: Forgot to mention: I'm +1 on the proposal in general, though it would be nice if these types/functions were available from a compatibility library as well, since deepseq is now bundled with GHC and therefore difficult to upgrade on its own.
On Tue Feb 10 2015 at 1:43:52 PM Michael Snoyman
wrote: On Tue Feb 10 2015 at 1:41:48 PM Herbert Valerio Riedel
wrote: On 2015-02-10 at 09:46:37 +0100, Edward Z. Yang wrote:
I propose the following (abstract) data type, functions, and instance be added to deepseq (naming amenable to bikeshedding):
newtype NF a = NF a -- abstract makeNF :: NFData a => a -> NF a getNF :: NF a -> a
instance NFData (NF a) where rnf x = x `seq` ()
I generally like it, so count me as +1
bikeshed-wondering though, why did you make it abstract w/ separate construct/deconstructors?
If the real constructor was available, then someone would be free to write something like:
let foo = NF $ 1 : undefined
which would break the guarantees that this type is trying to provide.
as a related concept (and hoping not to derail the discussion too much), I had attempted some time ago to implement TH predicates that could infer if WHNF=NF holds:
http://hackage.haskell.org/package/deepseq-th-0.1.0.4/docs/Control-DeepSeq-T...
and back then I was wondering, if GHC couldn't help us out here (maybe by providing an implicit NF=WHNF class-instance -- and btw, I recently found out, Haskell 1.4 had an implicit 'Eval'-class declaring `seq`-ability)
I'm not sure though if WHNF=NF can always be decided...
Cheers, hvr _______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

On 10/02/15 19:08, David Feuer wrote:
+1, generally. Two thoughts:
1. There are, as far as I know, two reasonable senses of NF that one might care about. The weak sense is a guarantee that the structure has no accessible bottoms within it that would be reached if the structure were evaluated to normal form, along with a guarantee that it is impossible to use it to force lazy IO. A stronger sense offers some kind of performance guarantee, which seems much trickier to specify. Whether something is *actually* in normal form is not observable without using something like ticky-ticky profiling, so I don't think we're allowed to care about that. Since I support the idea of unsafeMakeNF, and perhaps other special NF-creation functions, I think it's important to be clear about just what it's supposed to mean.
Since deepseq is in no way magical, it can't provide any guarantees (you can define an instance that does whatever it wants). And neither can NF, being based on deepseq. All we can say is makeNF = NF . force, by definition. Roman

On Tue, Feb 10, 2015 at 1:38 PM, Roman Cheplyaka
Since deepseq is in no way magical, it can't provide any guarantees (you can define an instance that does whatever it wants). And neither can NF, being based on deepseq.
All we can say is makeNF = NF . force, by definition.
If we want to have an unsafeMakeNF, which I believe we probably do, then we need to specify what constitutes correct usage of that function.

A related data type that I've made use of in the past is described here
https://www.fpcomplete.com/user/edwardk/snippets/once
This version has the benefit that it works with data that really does need
a deepSeq, but encapsulates it in such a way that subsequent deepSeq's do
no extra work.
-Edward
On Tue, Feb 10, 2015 at 3:46 AM, Edward Z. Yang
I propose the following (abstract) data type, functions, and instance be added to deepseq (naming amenable to bikeshedding):
newtype NF a = NF a -- abstract makeNF :: NFData a => a -> NF a getNF :: NF a -> a instance NFData (NF a) where rnf x = x `seq` ()
NF is an abstract data type representing data which has been evaluated to normal form; the guarantee specifically is, if NF is in whnf, then it is in nf. Crucially, when we have 'NF a', we ONLY need to seq it in order to assure that it is fully evaluated.
This guarantee is sufficient for a variety of cases where normal data is necessary, e.g. when transmitting data over Channels. For example, from the monad-par library 'put_' could be used in place of 'put' with this type signature.
put_ :: IVar (NF a) -> (NF a) -> Par ()
Cheers, Edward _______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

Well, NF works with data that really needs a deepSeq too. The difference seems to be (1) you can extract out the 'a' without having deepSeq'd it and then partially evaluate it (which is not possible with NF), and (2) it has a runtime effect, whereas NF is purely a type discipline. Edward Excerpts from Edward Kmett's message of 2015-02-10 10:37:55 -0800:
A related data type that I've made use of in the past is described here
https://www.fpcomplete.com/user/edwardk/snippets/once
This version has the benefit that it works with data that really does need a deepSeq, but encapsulates it in such a way that subsequent deepSeq's do no extra work.
-Edward
On Tue, Feb 10, 2015 at 3:46 AM, Edward Z. Yang
wrote: I propose the following (abstract) data type, functions, and instance be added to deepseq (naming amenable to bikeshedding):
newtype NF a = NF a -- abstract makeNF :: NFData a => a -> NF a getNF :: NF a -> a instance NFData (NF a) where rnf x = x `seq` ()
NF is an abstract data type representing data which has been evaluated to normal form; the guarantee specifically is, if NF is in whnf, then it is in nf. Crucially, when we have 'NF a', we ONLY need to seq it in order to assure that it is fully evaluated.
This guarantee is sufficient for a variety of cases where normal data is necessary, e.g. when transmitting data over Channels. For example, from the monad-par library 'put_' could be used in place of 'put' with this type signature.
put_ :: IVar (NF a) -> (NF a) -> Par ()
Cheers, Edward _______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

Hello all, Taking the appropriate suggestion, I have created a small package to provide this functionality: https://hackage.haskell.org/package/nf If it migrates into deepseq, we can update this package to reexport the appropriate modules from deepseq when it is available. Please let me know if there's anything (e.g. version bounds) which I can do to make this more "enterprise" ready. Cheers, Edward Excerpts from Edward Z. Yang's message of 2015-02-10 08:46:37 +0000:
I propose the following (abstract) data type, functions, and instance be added to deepseq (naming amenable to bikeshedding):
newtype NF a = NF a -- abstract makeNF :: NFData a => a -> NF a getNF :: NF a -> a instance NFData (NF a) where rnf x = x `seq` ()
NF is an abstract data type representing data which has been evaluated to normal form; the guarantee specifically is, if NF is in whnf, then it is in nf. Crucially, when we have 'NF a', we ONLY need to seq it in order to assure that it is fully evaluated.
This guarantee is sufficient for a variety of cases where normal data is necessary, e.g. when transmitting data over Channels. For example, from the monad-par library 'put_' could be used in place of 'put' with this type signature.
put_ :: IVar (NF a) -> (NF a) -> Par ()
Cheers, Edward

Small request: could you bump the upper bound to allow base 4? ;)
On Wed, Apr 22, 2015 at 10:50 AM Edward Z. Yang
Hello all,
Taking the appropriate suggestion, I have created a small package to provide this functionality:
https://hackage.haskell.org/package/nf
If it migrates into deepseq, we can update this package to reexport the appropriate modules from deepseq when it is available.
Please let me know if there's anything (e.g. version bounds) which I can do to make this more "enterprise" ready.
Cheers, Edward
Excerpts from Edward Z. Yang's message of 2015-02-10 08:46:37 +0000:
I propose the following (abstract) data type, functions, and instance be added to deepseq (naming amenable to bikeshedding):
newtype NF a = NF a -- abstract makeNF :: NFData a => a -> NF a getNF :: NF a -> a instance NFData (NF a) where rnf x = x `seq` ()
NF is an abstract data type representing data which has been evaluated to normal form; the guarantee specifically is, if NF is in whnf, then it is in nf. Crucially, when we have 'NF a', we ONLY need to seq it in order to assure that it is fully evaluated.
This guarantee is sufficient for a variety of cases where normal data is necessary, e.g. when transmitting data over Channels. For example, from the monad-par library 'put_' could be used in place of 'put' with this type signature.
put_ :: IVar (NF a) -> (NF a) -> Par ()
Cheers, Edward
Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

That's what I get for guessing syntax. Fixed. Edward Excerpts from Michael Snoyman's message of 2015-04-22 08:54:32 +0100:
Small request: could you bump the upper bound to allow base 4? ;)
On Wed, Apr 22, 2015 at 10:50 AM Edward Z. Yang
wrote: Hello all,
Taking the appropriate suggestion, I have created a small package to provide this functionality:
https://hackage.haskell.org/package/nf
If it migrates into deepseq, we can update this package to reexport the appropriate modules from deepseq when it is available.
Please let me know if there's anything (e.g. version bounds) which I can do to make this more "enterprise" ready.
Cheers, Edward
Excerpts from Edward Z. Yang's message of 2015-02-10 08:46:37 +0000:
I propose the following (abstract) data type, functions, and instance be added to deepseq (naming amenable to bikeshedding):
newtype NF a = NF a -- abstract makeNF :: NFData a => a -> NF a getNF :: NF a -> a instance NFData (NF a) where rnf x = x `seq` ()
NF is an abstract data type representing data which has been evaluated to normal form; the guarantee specifically is, if NF is in whnf, then it is in nf. Crucially, when we have 'NF a', we ONLY need to seq it in order to assure that it is fully evaluated.
This guarantee is sufficient for a variety of cases where normal data is necessary, e.g. when transmitting data over Channels. For example, from the monad-par library 'put_' could be used in place of 'put' with this type signature.
put_ :: IVar (NF a) -> (NF a) -> Par ()
Cheers, Edward
Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

Only thing I can think of is adding a bunch of `deriving`s to NF. I can
picture people wanting to just plot an `NF` into the middle of their data
structures and still be able to `show` it for debugging. I'm guessing a
minimal list may be Show, Read, Eq, Ord, Typeable. Data and Generic seem
like an interesting case, since- on the one hand- it would be nice to have
the instances (especially the latter) for auto-deriving mechanisms, but in
theory it can be used to break the abstraction. However, given that you're
already giving people an escape route via the .Internal module, I don't
think that's as big a concern.
On Wed, Apr 22, 2015 at 11:04 AM Edward Z. Yang
That's what I get for guessing syntax. Fixed.
Edward
Excerpts from Michael Snoyman's message of 2015-04-22 08:54:32 +0100:
Small request: could you bump the upper bound to allow base 4? ;)
On Wed, Apr 22, 2015 at 10:50 AM Edward Z. Yang
wrote: Hello all,
Taking the appropriate suggestion, I have created a small package to provide this functionality:
https://hackage.haskell.org/package/nf
If it migrates into deepseq, we can update this package to reexport the appropriate modules from deepseq when it is available.
Please let me know if there's anything (e.g. version bounds) which I can do to make this more "enterprise" ready.
Cheers, Edward
Excerpts from Edward Z. Yang's message of 2015-02-10 08:46:37 +0000:
I propose the following (abstract) data type, functions, and instance be added to deepseq (naming amenable to bikeshedding):
newtype NF a = NF a -- abstract makeNF :: NFData a => a -> NF a getNF :: NF a -> a instance NFData (NF a) where rnf x = x `seq` ()
NF is an abstract data type representing data which has been evaluated to normal form; the guarantee specifically is, if NF is in whnf, then it is in nf. Crucially, when we have 'NF a', we ONLY need to seq it in order to assure that it is fully evaluated.
This guarantee is sufficient for a variety of cases where normal data is necessary, e.g. when transmitting data over Channels. For example, from the monad-par library 'put_' could be used in place of 'put' with this type signature.
put_ :: IVar (NF a) -> (NF a) -> Par ()
Cheers, Edward
Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

A hand-written read makes more sense to me in this case:
read = makeNF . read
show = show . getNF
Other instances where a "new value" is created can be written similarly:
instance (Monoid m) => Monoid (NF m) where
mempty = makeNF mempty
mappend aNF bNF = makeNF (mappend (getNF aNF) (getNF bNF))
Whether the pattern of using NF this way is a good idea... I don't know. It
just seems nice if data of type `NF a` can be used as a drop-in replacement
for data of type `a`.
-- Dan Burton
On Wed, Apr 22, 2015 at 1:10 AM, Michael Snoyman
Only thing I can think of is adding a bunch of `deriving`s to NF. I can picture people wanting to just plot an `NF` into the middle of their data structures and still be able to `show` it for debugging. I'm guessing a minimal list may be Show, Read, Eq, Ord, Typeable. Data and Generic seem like an interesting case, since- on the one hand- it would be nice to have the instances (especially the latter) for auto-deriving mechanisms, but in theory it can be used to break the abstraction. However, given that you're already giving people an escape route via the .Internal module, I don't think that's as big a concern.
On Wed, Apr 22, 2015 at 11:04 AM Edward Z. Yang
wrote: That's what I get for guessing syntax. Fixed.
Edward
Small request: could you bump the upper bound to allow base 4? ;)
On Wed, Apr 22, 2015 at 10:50 AM Edward Z. Yang
wrote: Hello all,
Taking the appropriate suggestion, I have created a small package to provide this functionality:
https://hackage.haskell.org/package/nf
If it migrates into deepseq, we can update this package to reexport the appropriate modules from deepseq when it is available.
Please let me know if there's anything (e.g. version bounds) which I can do to make this more "enterprise" ready.
Cheers, Edward
Excerpts from Edward Z. Yang's message of 2015-02-10 08:46:37 +0000:
I propose the following (abstract) data type, functions, and instance be added to deepseq (naming amenable to bikeshedding):
newtype NF a = NF a -- abstract makeNF :: NFData a => a -> NF a getNF :: NF a -> a instance NFData (NF a) where rnf x = x `seq` ()
NF is an abstract data type representing data which has been evaluated to normal form; the guarantee specifically is, if NF is in whnf,
it is in nf. Crucially, when we have 'NF a', we ONLY need to seq it in order to assure that it is fully evaluated.
This guarantee is sufficient for a variety of cases where normal data is necessary, e.g. when transmitting data over Channels. For example, from the monad-par library 'put_' could be used in
Excerpts from Michael Snoyman's message of 2015-04-22 08:54:32 +0100: then place
of 'put' with this type signature.
put_ :: IVar (NF a) -> (NF a) -> Par ()
Cheers, Edward
Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
_______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

On Wed, 22 Apr 2015, Dan Burton wrote:
A hand-written read makes more sense to me in this case: read = makeNF . read show = show . getNF
Show and Read instances should process Strings representing Haskell code, and I guess, Haskell code with the same type as the represented value. Thus the NF should be part of the formatted value.

But it is an interesting question whether or not 'UnsafeNF' should be used, since the value read in is known to be in normal form. Edward Excerpts from Henning Thielemann's message of 2015-04-22 19:49:56 +0100:
On Wed, 22 Apr 2015, Dan Burton wrote:
A hand-written read makes more sense to me in this case: read = makeNF . read show = show . getNF
Show and Read instances should process Strings representing Haskell code, and I guess, Haskell code with the same type as the represented value. Thus the NF should be part of the formatted value.

On 22/04/15 21:54, Edward Z. Yang wrote:
But it is an interesting question whether or not 'UnsafeNF' should be used, since the value read in is known to be in normal form.
Is it? newtype X = X Int deriving Show instance Read X where readsPrec n = map (first $ X . trace "eval") . readsPrec n
length (read "[1,2,3]" :: [X]) 3 read "[1,2,3]" :: [X] [X eval 1,X eval 2,X eval 3]
Or did you mean something else?
Excerpts from Henning Thielemann's message of 2015-04-22 19:49:56 +0100:
On Wed, 22 Apr 2015, Dan Burton wrote:
A hand-written read makes more sense to me in this case: read = makeNF . read show = show . getNF
Show and Read instances should process Strings representing Haskell code, and I guess, Haskell code with the same type as the represented value. Thus the NF should be part of the formatted value.
_______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

OK, perhaps not :) Edward Excerpts from Roman Cheplyaka's message of 2015-04-22 21:28:10 +0100:
On 22/04/15 21:54, Edward Z. Yang wrote:
But it is an interesting question whether or not 'UnsafeNF' should be used, since the value read in is known to be in normal form.
Is it?
newtype X = X Int deriving Show instance Read X where readsPrec n = map (first $ X . trace "eval") . readsPrec n
length (read "[1,2,3]" :: [X]) 3 read "[1,2,3]" :: [X] [X eval 1,X eval 2,X eval 3]
Or did you mean something else?
Excerpts from Henning Thielemann's message of 2015-04-22 19:49:56 +0100:
On Wed, 22 Apr 2015, Dan Burton wrote:
A hand-written read makes more sense to me in this case: read = makeNF . read show = show . getNF
Show and Read instances should process Strings representing Haskell code, and I guess, Haskell code with the same type as the represented value. Thus the NF should be part of the formatted value.
_______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

I just realized that the thread of this conversation was not fully finished. For Show/Read, there are two flex points: (1) Should `show (mkNF 2)` output "mkNF 2" or "UnsafeNF 2"? I have a preference for the former but then we need to handwrite the instance. We could also change the definition of NF to just name its constructor NF and export a helper function unsafeMkNF (2) Should `read "mkNF 2"` execute rnf on the result of the inner Read instance? If the answer is no, we can use the default; if the answer is yes, we want an instance like: instance (NFData a, Read a) => Read (NF a) where readsPrec = parens . prec 10 $ do Ident "makeNF" <- lexP m <- step readPrec return (m `deepseq` UnsafeNF m) I lean towards a safe by default API, with an unsafeReadNF, but maybe if default Read instances are not lazy, we should be OK (e.g. (read $ show (repeat 1)) :: [Int] hangs; it isn't identity). Edward Excerpts from Roman Cheplyaka's message of 2015-04-22 13:28:10 -0700:
On 22/04/15 21:54, Edward Z. Yang wrote:
But it is an interesting question whether or not 'UnsafeNF' should be used, since the value read in is known to be in normal form.
Is it?
newtype X = X Int deriving Show instance Read X where readsPrec n = map (first $ X . trace "eval") . readsPrec n
length (read "[1,2,3]" :: [X]) 3 read "[1,2,3]" :: [X] [X eval 1,X eval 2,X eval 3]
Or did you mean something else?
Excerpts from Henning Thielemann's message of 2015-04-22 19:49:56 +0100:
On Wed, 22 Apr 2015, Dan Burton wrote:
A hand-written read makes more sense to me in this case: read = makeNF . read show = show . getNF
Show and Read instances should process Strings representing Haskell code, and I guess, Haskell code with the same type as the represented value. Thus the NF should be part of the formatted value.
_______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

On 2 May 2015 at 11:24, Edward Z. Yang
I just realized that the thread of this conversation was not fully finished.
For Show/Read, there are two flex points:
(1) Should `show (mkNF 2)` output "mkNF 2" or "UnsafeNF 2"? I have a preference for the former but then we need to handwrite the instance. We could also change the definition of NF to just name its constructor NF and export a helper function unsafeMkNF
I think it should output "mkNF 2", unless you're going to be exporting the constructor for people to use.
(2) Should `read "mkNF 2"` execute rnf on the result of the inner Read instance? If the answer is no, we can use the default; if the answer is yes, we want an instance like:
instance (NFData a, Read a) => Read (NF a) where readsPrec = parens . prec 10 $ do Ident "makeNF" <- lexP m <- step readPrec return (m `deepseq` UnsafeNF m)
I think this is the right approach, though maybe you should just use "makeNF m" internally rather than copying it's definition in the last line.
I lean towards a safe by default API, with an unsafeReadNF, but maybe if default Read instances are not lazy, we should be OK (e.g. (read $ show (repeat 1)) :: [Int] hangs; it isn't identity).
Edward
Excerpts from Roman Cheplyaka's message of 2015-04-22 13:28:10 -0700:
On 22/04/15 21:54, Edward Z. Yang wrote:
But it is an interesting question whether or not 'UnsafeNF' should be used, since the value read in is known to be in normal form.
Is it?
newtype X = X Int deriving Show instance Read X where readsPrec n = map (first $ X . trace "eval") . readsPrec n
length (read "[1,2,3]" :: [X]) 3 read "[1,2,3]" :: [X] [X eval 1,X eval 2,X eval 3]
Or did you mean something else?
Excerpts from Henning Thielemann's message of 2015-04-22 19:49:56 +0100:
On Wed, 22 Apr 2015, Dan Burton wrote:
A hand-written read makes more sense to me in this case: read = makeNF . read show = show . getNF
Show and Read instances should process Strings representing Haskell code, and I guess, Haskell code with the same type as the represented value. Thus the NF should be part of the formatted value.
_______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
-- Ivan Lazar Miljenovic Ivan.Miljenovic@gmail.com http://IvanMiljenovic.wordpress.com

Henning Thielemann wrote:
Show and Read instances should process Strings representing Haskell code, and I guess, Haskell code with the same type as the represented value. Thus the NF should be part of the formatted value.
Agreed. Instead, add stand-alone functions: readNF = makeNF . read showNF = show . getNF
participants (12)
-
Carter Schonwald
-
Dan Burton
-
David Feuer
-
Edward Kmett
-
Edward Z. Yang
-
Henning Thielemann
-
Herbert Valerio Riedel
-
Ivan Lazar Miljenovic
-
John Wiegley
-
Michael Snoyman
-
Roman Cheplyaka
-
Yitzchak Gale