The evaluate function is defined in GHC.IO, and exported publicly by
Control.Exception. This strikes me as an extremely strange place for it. Can we find another place to put it that would seem more sensible? I don't think it should be removed from Control.Exception, but rather that maybe it should be added somewhere else as well. Digging all around, I've come up with one idea that might work, if we give evaluate a more general type: evaluate :: PrimMonad m => a -> m a evaluate a = primitive (\s -> seq# a s) With this type, we could easily put it in Control.Monad.Primitive. There may be some challenges wiggling module dependencies around, but hopefully not huge ones. David _______________________________________________ Libraries mailing list [hidden email] http://www.haskell.org/mailman/listinfo/libraries |
I went ahead and tried this. It works like a charm, but there's one
minor wrinkle: it seems we'd have to move the declaration of the PrimMonad class out of the primitive package and into base, perhaps into GHC.Base, with the IO instance in GHC.Base and the ST instance in GHC.ST. What do people think? On Tue, Jan 6, 2015 at 11:36 PM, David Feuer <[hidden email]> wrote: > The evaluate function is defined in GHC.IO, and exported publicly by > Control.Exception. This strikes me as an extremely strange place for > it. Can we find another place to put it that would seem more sensible? > I don't think it should be removed from Control.Exception, but rather > that maybe it should be added somewhere else as well. > > Digging all around, I've come up with one idea that might work, if we > give evaluate a more general type: > > evaluate :: PrimMonad m => a -> m a > evaluate a = primitive (\s -> seq# a s) > > With this type, we could easily put it in Control.Monad.Primitive. > There may be some challenges wiggling module dependencies around, but > hopefully not huge ones. > > David Libraries mailing list [hidden email] http://www.haskell.org/mailman/listinfo/libraries |
> On Tue, Jan 6, 2015 at 11:36 PM, David Feuer <[hidden email]> wrote: >> The evaluate function is defined in GHC.IO, and exported publicly by >> Control.Exception. This strikes me as an extremely strange place for >> it. I also find the place strange. If there would be a module with a type class for seq (like Eval), it would be certainly a good place for 'evaluate'. _______________________________________________ Libraries mailing list [hidden email] http://www.haskell.org/mailman/listinfo/libraries |
I agree that Control.Exception seems like a very strange place for `evaluate` to be publicly exported. However, I've never wanted that function except in the context of forcing evaluation of a pure value in order to catch exceptions. I also can't think of any other use cases that aren't more easily solved by seq/bang patterns. If the only use case is in fact exception handling, Control.Exception seems like a pretty good location.
On Wed Jan 07 2015 at 11:45:39 AM Henning Thielemann <[hidden email]> wrote:
_______________________________________________ Libraries mailing list [hidden email] http://www.haskell.org/mailman/listinfo/libraries |
Isn't it the official way to make sure lazy IO gets performed before a
file is closed, or is ($!) actually safe for that? (I really and truly can't understand all the details of what goes on in the rather old bug reports relating to the implementation of evaluate). On Wed, Jan 7, 2015 at 3:27 PM, John Lato <[hidden email]> wrote: > I agree that Control.Exception seems like a very strange place for > `evaluate` to be publicly exported. However, I've never wanted that > function except in the context of forcing evaluation of a pure value in > order to catch exceptions. I also can't think of any other use cases that > aren't more easily solved by seq/bang patterns. If the only use case is in > fact exception handling, Control.Exception seems like a pretty good > location. > On Wed Jan 07 2015 at 11:45:39 AM Henning Thielemann > <[hidden email]> wrote: >> >> >> > On Tue, Jan 6, 2015 at 11:36 PM, David Feuer <[hidden email]> >> > wrote: >> >> >> The evaluate function is defined in GHC.IO, and exported publicly by >> >> Control.Exception. This strikes me as an extremely strange place for >> >> it. >> >> I also find the place strange. If there would be a module with a type >> class for seq (like Eval), it would be certainly a good place for >> 'evaluate'. >> _______________________________________________ >> Libraries mailing list >> [hidden email] >> http://www.haskell.org/mailman/listinfo/libraries Libraries mailing list [hidden email] http://www.haskell.org/mailman/listinfo/libraries |
AKAIK neither one is necessarily safe. You need something like deepseq to fully evaluate the lazy structure. If you are sure that evaluation to WHNF is sufficient for performing all lazy IO, then I think either evaluate or ($!) will work. evaluate is probably to be preferred if IO is available, similar to throw vs throwIO. However I think idioms with seq and ($!) are so common that they need to be supported too. After all, you may have just a 'Monad m' context. John _______________________________________________ Libraries mailing list [hidden email] http://www.haskell.org/mailman/listinfo/libraries |
deepseq is somewhat orthogonal:
shallow: v $! return v deep: v $!! return v shallow: evaluate v >>= return deep: evaluate (force v) >>= return On Thu, Jan 8, 2015 at 12:11 PM, John Lato <[hidden email]> wrote: > AKAIK neither one is necessarily safe. You need something like deepseq to > fully evaluate the lazy structure. > > If you are sure that evaluation to WHNF is sufficient for performing all > lazy IO, then I think either evaluate or ($!) will work. > > evaluate is probably to be preferred if IO is available, similar to throw vs > throwIO. However I think idioms with seq and ($!) are so common that they > need to be supported too. After all, you may have just a 'Monad m' context. > > John Libraries mailing list [hidden email] http://www.haskell.org/mailman/listinfo/libraries |
It's a bit orthogonal, but since you brought up lazy IO I thought it was worth mentioning, as shallow evaluation is insufficient. On 09:15, Thu, Jan 8, 2015 David Feuer <[hidden email]> wrote:
deepseq is somewhat orthogonal: _______________________________________________ Libraries mailing list [hidden email] http://www.haskell.org/mailman/listinfo/libraries |
In reply to this post by John Lato-2
On 2015-01-08 at 18:11:22 +0100, John Lato wrote:
[...] > evaluate is probably to be preferred if IO is available, similar to throw > vs throwIO. However I think idioms with seq and ($!) are so common that > they need to be supported too. After all, you may have just a 'Monad m' > context. One thing that always confused me is the semantics of seq/($!)/($!!) in something like foo = do { x <- getX; rnf x `seq` return x } as in my mental model, `;` or rather (>>=) combines two monadic actions (according to the monad-laws), into a combined monadic action "value" 'Monad m => m a', which then needs to be executed via some monad-runner to have any monadic effect and/or extract the result of type 'a'. But I don't see how the monad-laws tell me anything about when that `seq` is executed (is it evaluated at monadic combination time[1], or only lateron at monadic execution?). Otoh, in the IO-monad, 'evaluate' seems to be quite clear to me in its semantics: it forces WHNF on its argument at execution-time. [1]: what effects does "seq foo ()" perform? If the action was foo' = do { undefined `seq` return () } :: Monad m => m () then "seq foo' ()" will in fact diverge. So in that case, the `seq` is evaluated at monadic combination time; but otoh for foo'' = do { return undefined } :: Monad m => m () "seq foo'' ()" will (for a sane 'return') evaluate to '()' Cheers, hvr _______________________________________________ Libraries mailing list [hidden email] http://www.haskell.org/mailman/listinfo/libraries |
Free forum by Nabble | Edit this page |