Discussion: Can we make evaluate easier to find?

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
9 messages Options
Reply | Threaded
Open this post in threaded view
|

Discussion: Can we make evaluate easier to find?

David Feuer
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
Reply | Threaded
Open this post in threaded view
|

Re: Discussion: Can we make evaluate easier to find?

David Feuer
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
Reply | Threaded
Open this post in threaded view
|

Re: Discussion: Can we make evaluate easier to find?

Henning Thielemann

> 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
Reply | Threaded
Open this post in threaded view
|

Re: Discussion: Can we make evaluate easier to find?

John Lato-2
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
Reply | Threaded
Open this post in threaded view
|

Re: Discussion: Can we make evaluate easier to find?

David Feuer
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
Reply | Threaded
Open this post in threaded view
|

Re: Discussion: Can we make evaluate easier to find?

John Lato-2

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
Reply | Threaded
Open this post in threaded view
|

Re: Discussion: Can we make evaluate easier to find?

David Feuer
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
Reply | Threaded
Open this post in threaded view
|

Re: Discussion: Can we make evaluate easier to find?

John Lato-2

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:

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
Reply | Threaded
Open this post in threaded view
|

Re: Discussion: Can we make evaluate easier to find?

Herbert Valerio Riedel
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