Re: !RE: Implicit reboxing of unboxed tuple in let-patterns

2020-09-10 Thread Iavor Diatchki
I am not sure what you'd expect this to do, but under what I was suggesting
it would be equivalent to
`let ~(x,y) = undefined in x `seq` y `seq ()`

Obviously it would be nice to warn/report error that this is probably a
mistake, which seems pretty easy to do.
What useful functionality do you think is lost by this?

The main tricky case I can think of is the interaction with pattern
synonyms, as one would have to keep track of
strict bindings in those.




On Thu, Sep 10, 2020 at 10:12 AM Chris Smith  wrote:

> I agree that the strictness there was surprising, but I think this may be
> a case where what is superficially expected is, in the end, inconsistent.
>
> What about:
>
> let ~(!x, !y) = undefined in ()
>
> If nested bang patterns implied strictness of their parents, this valid
> expression seems not to make any sense.  I can see a few ways to deal with
> that, but none of them seem intuitive to me.
>
> One could disallow it, and only allow strictness annotations on variables
> rather than all patterns, but this sacrifices a lot of functionality to
> avoid that surprise.  Alternatively, one could say that upward propagation
> of strictness is only a default, but that definitely feels like a hack.  It
> might make the original example behave as expected, but it is no longer for
> the expected reasons, and suddenly there is something even more complex
> going on.
>
> I don't have a strong opinion here, but I think it's important to consider
> more complex cases when making the decision.
>
> On Thu, Sep 10, 2020, 12:39 PM Iavor Diatchki 
> wrote:
>
>> Ah, yes, quite right: since the projections match the whole patterns, the
>> bang patterns in a constructor would be forced as soon as one of the fields
>> in the constructor is used, so this also diverges:
>>
>> ex3 = let (x, !y) = (5,undefined) in x
>>
>> The rule is consistent, to me it just seems quite unintuitive.
>>
>>
>>
>> On Thu, Sep 10, 2020 at 9:18 AM Richard Eisenberg 
>> wrote:
>>
>>> This whole area is clearly somewhat troublesome:
>>>
>>> On Sep 10, 2020, at 12:05 PM, Iavor Diatchki 
>>> wrote:
>>>
>>> 3. nested bang patterns in pattern bindings should count as "uses" of
>>> the value and therefore should be strict.  For example if I write `let (
>>> !x, !y ) = undefined in ()`, I think this should be equivalent to `let
>>> (x,y) = undefined in x `seq` y `seq` ()`.  With the current behavior the
>>> bang patterns don't do anything, while my guess would be that most people
>>> would expect the suggested behavior instead.  As usual, we should not allow
>>> that at the top level.
>>>
>>>
>>> This isn't quite right.
>>>
>>> Consider
>>>
>>> ex0 = let ( !x, !y ) = undefined in ()
>>> ex1 = let ( !x, !y ) = (5, undefined) in x
>>> ex2 = let ( !x, y )  = (5, undefined) in x
>>>
>>>
>>> ex0 converges, because let-bindings are lazy by default.
>>> ex1 diverges, because the bang on y means that, when the patten-match
>>> happens at all, x and y are bound strictly. So bangs *do* matter in nested
>>> patterns within pattern bindings. By contrast, ex2 converges.
>>>
>>> Again, I'm not arguing in favor of the current behavior, but I want to
>>> make sure we're all as informed as possible in this debate.
>>>
>>> Richard
>>>
>> ___
>> ghc-devs mailing list
>> ghc-devs@haskell.org
>> http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
>>
>
___
ghc-devs mailing list
ghc-devs@haskell.org
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs


Re: !RE: Implicit reboxing of unboxed tuple in let-patterns

2020-09-10 Thread Chris Smith
I agree that the strictness there was surprising, but I think this may be a
case where what is superficially expected is, in the end, inconsistent.

What about:

let ~(!x, !y) = undefined in ()

If nested bang patterns implied strictness of their parents, this valid
expression seems not to make any sense.  I can see a few ways to deal with
that, but none of them seem intuitive to me.

One could disallow it, and only allow strictness annotations on variables
rather than all patterns, but this sacrifices a lot of functionality to
avoid that surprise.  Alternatively, one could say that upward propagation
of strictness is only a default, but that definitely feels like a hack.  It
might make the original example behave as expected, but it is no longer for
the expected reasons, and suddenly there is something even more complex
going on.

I don't have a strong opinion here, but I think it's important to consider
more complex cases when making the decision.

On Thu, Sep 10, 2020, 12:39 PM Iavor Diatchki 
wrote:

> Ah, yes, quite right: since the projections match the whole patterns, the
> bang patterns in a constructor would be forced as soon as one of the fields
> in the constructor is used, so this also diverges:
>
> ex3 = let (x, !y) = (5,undefined) in x
>
> The rule is consistent, to me it just seems quite unintuitive.
>
>
>
> On Thu, Sep 10, 2020 at 9:18 AM Richard Eisenberg 
> wrote:
>
>> This whole area is clearly somewhat troublesome:
>>
>> On Sep 10, 2020, at 12:05 PM, Iavor Diatchki 
>> wrote:
>>
>> 3. nested bang patterns in pattern bindings should count as "uses" of the
>> value and therefore should be strict.  For example if I write `let ( !x, !y
>> ) = undefined in ()`, I think this should be equivalent to `let (x,y) =
>> undefined in x `seq` y `seq` ()`.  With the current behavior the bang
>> patterns don't do anything, while my guess would be that most people would
>> expect the suggested behavior instead.  As usual, we should not allow that
>> at the top level.
>>
>>
>> This isn't quite right.
>>
>> Consider
>>
>> ex0 = let ( !x, !y ) = undefined in ()
>> ex1 = let ( !x, !y ) = (5, undefined) in x
>> ex2 = let ( !x, y )  = (5, undefined) in x
>>
>>
>> ex0 converges, because let-bindings are lazy by default.
>> ex1 diverges, because the bang on y means that, when the patten-match
>> happens at all, x and y are bound strictly. So bangs *do* matter in nested
>> patterns within pattern bindings. By contrast, ex2 converges.
>>
>> Again, I'm not arguing in favor of the current behavior, but I want to
>> make sure we're all as informed as possible in this debate.
>>
>> Richard
>>
> ___
> ghc-devs mailing list
> ghc-devs@haskell.org
> http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
>
___
ghc-devs mailing list
ghc-devs@haskell.org
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs


Re: !RE: Implicit reboxing of unboxed tuple in let-patterns

2020-09-10 Thread Iavor Diatchki
Ah, yes, quite right: since the projections match the whole patterns, the
bang patterns in a constructor would be forced as soon as one of the fields
in the constructor is used, so this also diverges:

ex3 = let (x, !y) = (5,undefined) in x

The rule is consistent, to me it just seems quite unintuitive.



On Thu, Sep 10, 2020 at 9:18 AM Richard Eisenberg  wrote:

> This whole area is clearly somewhat troublesome:
>
> On Sep 10, 2020, at 12:05 PM, Iavor Diatchki 
> wrote:
>
> 3. nested bang patterns in pattern bindings should count as "uses" of the
> value and therefore should be strict.  For example if I write `let ( !x, !y
> ) = undefined in ()`, I think this should be equivalent to `let (x,y) =
> undefined in x `seq` y `seq` ()`.  With the current behavior the bang
> patterns don't do anything, while my guess would be that most people would
> expect the suggested behavior instead.  As usual, we should not allow that
> at the top level.
>
>
> This isn't quite right.
>
> Consider
>
> ex0 = let ( !x, !y ) = undefined in ()
> ex1 = let ( !x, !y ) = (5, undefined) in x
> ex2 = let ( !x, y )  = (5, undefined) in x
>
>
> ex0 converges, because let-bindings are lazy by default.
> ex1 diverges, because the bang on y means that, when the patten-match
> happens at all, x and y are bound strictly. So bangs *do* matter in nested
> patterns within pattern bindings. By contrast, ex2 converges.
>
> Again, I'm not arguing in favor of the current behavior, but I want to
> make sure we're all as informed as possible in this debate.
>
> Richard
>
___
ghc-devs mailing list
ghc-devs@haskell.org
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs


Re: !RE: Implicit reboxing of unboxed tuple in let-patterns

2020-09-10 Thread Richard Eisenberg
This whole area is clearly somewhat troublesome:

> On Sep 10, 2020, at 12:05 PM, Iavor Diatchki  wrote:
> 
> 3. nested bang patterns in pattern bindings should count as "uses" of the 
> value and therefore should be strict.  For example if I write `let ( !x, !y ) 
> = undefined in ()`, I think this should be equivalent to `let (x,y) = 
> undefined in x `seq` y `seq` ()`.  With the current behavior the bang 
> patterns don't do anything, while my guess would be that most people would 
> expect the suggested behavior instead.  As usual, we should not allow that at 
> the top level.

This isn't quite right.

Consider

> ex0 = let ( !x, !y ) = undefined in ()
> ex1 = let ( !x, !y ) = (5, undefined) in x
> ex2 = let ( !x, y )  = (5, undefined) in x

ex0 converges, because let-bindings are lazy by default.
ex1 diverges, because the bang on y means that, when the patten-match happens 
at all, x and y are bound strictly. So bangs *do* matter in nested patterns 
within pattern bindings. By contrast, ex2 converges.

Again, I'm not arguing in favor of the current behavior, but I want to make 
sure we're all as informed as possible in this debate.

Richard___
ghc-devs mailing list
ghc-devs@haskell.org
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs


Re: !RE: Implicit reboxing of unboxed tuple in let-patterns

2020-09-10 Thread Iavor Diatchki
hat if you wanted.  I can’t
>> decide if I like it, myself, but I think that it, too, is simple and
>> consistent.
>>
>>
>> Simon
>>
>>
>>
>> *From:* Iavor Diatchki 
>> *Sent:* 07 September 2020 20:46
>> *To:* Simon Peyton Jones 
>> *Cc:* Richard Eisenberg ; Spiwack, Arnaud <
>> arnaud.spiw...@tweag.io>; GHC developers 
>> *Subject:* Re: !RE: Implicit reboxing of unboxed tuple in let-patterns
>>
>>
>>
>>
>>
>>
>>
>> On Mon, Sep 7, 2020 at 5:12 AM Simon Peyton Jones via ghc-devs <
>> ghc-devs@haskell.org> wrote:
>>
>>
>>
>>
>>
>>1. I don’t understand the details of Iavor’s proposal to add that
>>“unlifted patterns are strict”, in addition to (1).  Do you mean “any
>>sub-pattern of the LHS has an unlifted type”? I think this is fully
>>compatible with unlifted user defined data
>>
>> Just (# a,b #) = e
>>
>> would be strict.   And even
>>
>> MkT _ = e
>>
>> would be strict if   data T = MkT (# Int,Int #)
>>
>>
>>
>>
>>
>> Yes, the first one would be strict up to the tuple, and the second one
>> would also be strict.  I think this is the consistent way to interpret your
>> rule (1) that unlifted bindings are always strict, and it shouldn't really
>> matter if you used a variable pattern, or a wild card pattern.  I don't
>> think there's any other part of the language where replacing a `_` with an
>> unused name changes the semantics of the program, and I don't think it
>> should in this case either.
>>
>>
>>
>> Just to be fully explicit, the thing I find odd with GHC's current
>> behavior is that these two are different:
>>
>>
>>
>> let MkT x = undefined in ()   --> undefined
>>
>> let MkT _ = undefined in ()   --> ()
>>
>>
>>
>> Even more explicitly:
>>
>> let (_ :: Int#) = undefined in ()   --> ()    -- the value `undefined` is
>> not representable in type `Int#` but GHC is happy to proceed because it
>> doesn't need to represent it
>>
>> let (x :: Int#) = undefined in ()--> ()   -- same situation, but now
>> GHC is strict, even though it still doesn't need to represent the value.
>>
>>
>>
>> I think that the consistent behavior is for all of these to diverge,
>> because laziness does not mix with unlfited values, at least in the
>> presence of non-termination.
>>
>>
>>
>> -Iavor
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>> *From:* ghc-devs  *On Behalf Of *Richard
>> Eisenberg
>> *Sent:* 02 September 2020 14:47
>> *To:* Spiwack, Arnaud 
>> *Cc:* GHC developers 
>> *Subject:* Re: Implicit reboxing of unboxed tuple in let-patterns
>>
>>
>>
>>
>>
>>
>>
>> On Sep 2, 2020, at 9:39 AM, Spiwack, Arnaud 
>> wrote:
>>
>>
>>
>> Ooh… pattern synonyms for unboxed tuple. I must confess that I don't know
>> what the semantics of these ought to be. It does look like an interesting
>> can of worms. How do they currently desugar?
>>
>>
>>
>> Right now, there is one rule: if the type of any variable bound in the
>> pattern is unlifted, then the pattern is an unlifter-var pattern and is
>> strict. The pattern must be banged, unless the bound variable is not
>> nested. This rule is consistent across all features.
>>
>>
>>
>> This thread is suggesting to add a special case -- one that seems to
>> match intuition, but it's still a special case. And my question is: should
>> the special case be for unboxed tuples? or should the special case be for
>> any pattern whose overall type is unlifted?
>>
>>
>>
>> Richard
>>
>> ___
>> ghc-devs mailing list
>> ghc-devs@haskell.org
>> http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
>> <https://nam06.safelinks.protection.outlook.com/?url=http%3A%2F%2Fmail.haskell.org%2Fcgi-bin%2Fmailman%2Flistinfo%2Fghc-devs=02%7C01%7Csimonpj%40microsoft.com%7Ca1b8984af610438e315a08d853669e2b%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637351047493622347=mlcv1AZBJ%2FHQYDQtS7NPQ5YnbhQA17tWx9fzoVe8Gic%3D=0>
>>
>>
___
ghc-devs mailing list
ghc-devs@haskell.org
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs


Re: !RE: Implicit reboxing of unboxed tuple in let-patterns

2020-09-10 Thread Spiwack, Arnaud
One thing that I had missed, until Simon pointed it out, is that in a let
pat = … expression, only the outermost pattern of pat is lazy. So

let (x,Just y) = (1, undefined) in x `seq` ()

Diverges. (whereas let (x,~(Just y)) = (1, undefined) in x `seq` ())
doesn’t).

So, really, we are only speaking of the outermost pattern, which does
simplify the discussion a little.

I don’t think that I share Iavor’s concern. In fact, I’ve got to say that I
personally don’t see (1) as meaning that the pattern is actually strict. I
just see a lazy pattern which happens to be immediately forced, because an
unlifted variable is bound. In this view, it doesn’t follow that the
presence of some unlifted pattern deep inside a lazy pattern ought to force
the pattern.

However, if the outermost pattern is unlifted, then it’s most likely that
it is not intended for the pattern to be lazy. From there, I see four ways
forward:

   1. Make let pat = … strict if the outermost pattern is unlifted
   2. Make let pat = … emit a warning if the outermost pattern is unlifted,
   but not explicitly banged.
   3. Decide that I’m mistaken, and that the current design is fine
   4. Decide that I’m mistaken, and that Iavor’s design it best

What do you think? I’ll try and make a proposal soon (unless (3) is too
popular for a proposal to be worth it).

On Tue, Sep 8, 2020 at 12:02 AM Simon Peyton Jones simo...@microsoft.com
<http://mailto:simo...@microsoft.com> wrote:

I think this is the consistent way to interpret your rule (1) that unlifted
> bindings are always strict
>
>
>
> But that’s not what rule (1) says.  It says that *a pattern binding is
> strict iff it binds a variable of unlifted type*.
>
>
>
> Now I think we agree that your proposal says that *a pattern binding is
> strict iff it or any of its sub-patterns has unlifted type, *including
> wild-cards, variables, and constructor patterns; in fact *any*
> sub-pattern.   Call that (2).
>
>
>
> So
>
>- (1) is *necessary*.
>- (2) is strictly stronger, and will make fewer program defined.  But
>is perhaps less surprising.
>
>
>
> I think you could make a proposal out of that if you wanted.  I can’t
> decide if I like it, myself, but I think that it, too, is simple and
> consistent.
>
>
> Simon
>
>
>
> *From:* Iavor Diatchki 
> *Sent:* 07 September 2020 20:46
> *To:* Simon Peyton Jones 
> *Cc:* Richard Eisenberg ; Spiwack, Arnaud <
> arnaud.spiw...@tweag.io>; GHC developers 
> *Subject:* Re: !RE: Implicit reboxing of unboxed tuple in let-patterns
>
>
>
>
>
>
>
> On Mon, Sep 7, 2020 at 5:12 AM Simon Peyton Jones via ghc-devs <
> ghc-devs@haskell.org> wrote:
>
>
>
>
>
>1. I don’t understand the details of Iavor’s proposal to add that
>“unlifted patterns are strict”, in addition to (1).  Do you mean “any
>sub-pattern of the LHS has an unlifted type”? I think this is fully
>compatible with unlifted user defined data
>
> Just (# a,b #) = e
>
> would be strict.   And even
>
> MkT _ = e
>
> would be strict if   data T = MkT (# Int,Int #)
>
>
>
>
>
> Yes, the first one would be strict up to the tuple, and the second one
> would also be strict.  I think this is the consistent way to interpret your
> rule (1) that unlifted bindings are always strict, and it shouldn't really
> matter if you used a variable pattern, or a wild card pattern.  I don't
> think there's any other part of the language where replacing a `_` with an
> unused name changes the semantics of the program, and I don't think it
> should in this case either.
>
>
>
> Just to be fully explicit, the thing I find odd with GHC's current
> behavior is that these two are different:
>
>
>
> let MkT x = undefined in ()   --> undefined
>
> let MkT _ = undefined in ()   --> ()
>
>
>
> Even more explicitly:
>
> let (_ :: Int#) = undefined in ()   --> ()-- the value `undefined` is
> not representable in type `Int#` but GHC is happy to proceed because it
> doesn't need to represent it
>
> let (x :: Int#) = undefined in ()--> ()   -- same situation, but now
> GHC is strict, even though it still doesn't need to represent the value.
>
>
>
> I think that the consistent behavior is for all of these to diverge,
> because laziness does not mix with unlfited values, at least in the
> presence of non-termination.
>
>
>
> -Iavor
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
> *From:* ghc-devs  *On Behalf Of *Richard
> Eisenberg
> *Sent:* 02 September 2020 14:47
> *To:* Spiwack, Arnaud 
> *Cc:* GHC developers 
> *Subject:* Re: Implicit reboxing of unboxed tuple in let-patterns
>
>
&

RE: !RE: Implicit reboxing of unboxed tuple in let-patterns

2020-09-07 Thread Simon Peyton Jones via ghc-devs
I think this is the consistent way to interpret your rule (1) that unlifted 
bindings are always strict

But that’s not what rule (1) says.  It says that a pattern binding is strict 
iff it binds a variable of unlifted type.

Now I think we agree that your proposal says that a pattern binding is strict 
iff it or any of its sub-patterns has unlifted type, including wild-cards, 
variables, and constructor patterns; in fact any sub-pattern.   Call that (2).

So

  *   (1) is necessary.
  *   (2) is strictly stronger, and will make fewer program defined.  But is 
perhaps less surprising.

I think you could make a proposal out of that if you wanted.  I can’t decide if 
I like it, myself, but I think that it, too, is simple and consistent.

Simon

From: Iavor Diatchki 
Sent: 07 September 2020 20:46
To: Simon Peyton Jones 
Cc: Richard Eisenberg ; Spiwack, Arnaud 
; GHC developers 
Subject: Re: !RE: Implicit reboxing of unboxed tuple in let-patterns



On Mon, Sep 7, 2020 at 5:12 AM Simon Peyton Jones via ghc-devs 
mailto:ghc-devs@haskell.org>> wrote:



  1.  I don’t understand the details of Iavor’s proposal to add that “unlifted 
patterns are strict”, in addition to (1).  Do you mean “any sub-pattern of the 
LHS has an unlifted type”? I think this is fully compatible with unlifted user 
defined data
Just (# a,b #) = e
would be strict.   And even
MkT _ = e
would be strict if   data T = MkT (# Int,Int #)


Yes, the first one would be strict up to the tuple, and the second one would 
also be strict.  I think this is the consistent way to interpret your rule (1) 
that unlifted bindings are always strict, and it shouldn't really matter if you 
used a variable pattern, or a wild card pattern.  I don't think there's any 
other part of the language where replacing a `_` with an unused name changes 
the semantics of the program, and I don't think it should in this case either.

Just to be fully explicit, the thing I find odd with GHC's current behavior is 
that these two are different:

let MkT x = undefined in ()   --> undefined
let MkT _ = undefined in ()   --> ()

Even more explicitly:
let (_ :: Int#) = undefined in ()   --> ()-- the value `undefined` is not 
representable in type `Int#` but GHC is happy to proceed because it doesn't 
need to represent it
let (x :: Int#) = undefined in ()--> ()   -- same situation, but now GHC is 
strict, even though it still doesn't need to represent the value.

I think that the consistent behavior is for all of these to diverge, because 
laziness does not mix with unlfited values, at least in the presence of 
non-termination.

-Iavor










From: ghc-devs 
mailto:ghc-devs-boun...@haskell.org>> On Behalf 
Of Richard Eisenberg
Sent: 02 September 2020 14:47
To: Spiwack, Arnaud mailto:arnaud.spiw...@tweag.io>>
Cc: GHC developers mailto:ghc-devs@haskell.org>>
Subject: Re: Implicit reboxing of unboxed tuple in let-patterns



On Sep 2, 2020, at 9:39 AM, Spiwack, Arnaud 
mailto:arnaud.spiw...@tweag.io>> wrote:

Ooh… pattern synonyms for unboxed tuple. I must confess that I don't know what 
the semantics of these ought to be. It does look like an interesting can of 
worms. How do they currently desugar?

Right now, there is one rule: if the type of any variable bound in the pattern 
is unlifted, then the pattern is an unlifter-var pattern and is strict. The 
pattern must be banged, unless the bound variable is not nested. This rule is 
consistent across all features.

This thread is suggesting to add a special case -- one that seems to match 
intuition, but it's still a special case. And my question is: should the 
special case be for unboxed tuples? or should the special case be for any 
pattern whose overall type is unlifted?

Richard
___
ghc-devs mailing list
ghc-devs@haskell.org<mailto:ghc-devs@haskell.org>
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs<https://nam06.safelinks.protection.outlook.com/?url=http%3A%2F%2Fmail.haskell.org%2Fcgi-bin%2Fmailman%2Flistinfo%2Fghc-devs=02%7C01%7Csimonpj%40microsoft.com%7Ca1b8984af610438e315a08d853669e2b%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637351047493622347=mlcv1AZBJ%2FHQYDQtS7NPQ5YnbhQA17tWx9fzoVe8Gic%3D=0>
___
ghc-devs mailing list
ghc-devs@haskell.org
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs


Re: !RE: Implicit reboxing of unboxed tuple in let-patterns

2020-09-07 Thread Iavor Diatchki
On Mon, Sep 7, 2020 at 5:12 AM Simon Peyton Jones via ghc-devs <
ghc-devs@haskell.org> wrote:

>
>
>
>1. I don’t understand the details of Iavor’s proposal to add that
>“unlifted patterns are strict”, in addition to (1).  Do you mean “any
>sub-pattern of the LHS has an unlifted type”? I think this is fully
>compatible with unlifted user defined data
>
> Just (# a,b #) = e
>
> would be strict.   And even
>
> MkT _ = e
>
> would be strict if   data T = MkT (# Int,Int #)
>
>
>

Yes, the first one would be strict up to the tuple, and the second one
would also be strict.  I think this is the consistent way to interpret your
rule (1) that unlifted bindings are always strict, and it shouldn't really
matter if you used a variable pattern, or a wild card pattern.  I don't
think there's any other part of the language where replacing a `_` with an
unused name changes the semantics of the program, and I don't think it
should in this case either.

Just to be fully explicit, the thing I find odd with GHC's current behavior
is that these two are different:

let MkT x = undefined in ()   --> undefined
let MkT _ = undefined in ()   --> ()

Even more explicitly:
let (_ :: Int#) = undefined in ()   --> ()-- the value `undefined` is
not representable in type `Int#` but GHC is happy to proceed because it
doesn't need to represent it
let (x :: Int#) = undefined in ()--> ()   -- same situation, but now
GHC is strict, even though it still doesn't need to represent the value.

I think that the consistent behavior is for all of these to diverge,
because laziness does not mix with unlfited values, at least in the
presence of non-termination.

-Iavor










>
>
> *From:* ghc-devs  *On Behalf Of *Richard
> Eisenberg
> *Sent:* 02 September 2020 14:47
> *To:* Spiwack, Arnaud 
> *Cc:* GHC developers 
> *Subject:* Re: Implicit reboxing of unboxed tuple in let-patterns
>
>
>
>
>
>
>
> On Sep 2, 2020, at 9:39 AM, Spiwack, Arnaud 
> wrote:
>
>
>
> Ooh… pattern synonyms for unboxed tuple. I must confess that I don't know
> what the semantics of these ought to be. It does look like an interesting
> can of worms. How do they currently desugar?
>
>
>
> Right now, there is one rule: if the type of any variable bound in the
> pattern is unlifted, then the pattern is an unlifter-var pattern and is
> strict. The pattern must be banged, unless the bound variable is not
> nested. This rule is consistent across all features.
>
>
>
> This thread is suggesting to add a special case -- one that seems to match
> intuition, but it's still a special case. And my question is: should the
> special case be for unboxed tuples? or should the special case be for any
> pattern whose overall type is unlifted?
>
>
>
> Richard
> ___
> ghc-devs mailing list
> ghc-devs@haskell.org
> http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
>
___
ghc-devs mailing list
ghc-devs@haskell.org
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs


!RE: Implicit reboxing of unboxed tuple in let-patterns

2020-09-07 Thread Simon Peyton Jones via ghc-devs
I’m a bit late to this debate, but here are a few thoughts.


  1.  “Right now, there is one rule: if the type of any variable bound in the 
pattern is unlifted, then the binding is strict.”Not only is this rule 
simple and consistent, it is also necessary: we cannot bind a variable of 
unlifted type to a thunk.   So any new rule must include this, and maybe add 
something extra, complicating the language.


  1.  All lazy pattern bindings go via an intermediate tuple.  If you write
(Just x, [y]) = e
then you get
t = case e of (Just x, [y]) -> (x,y)
x = fst t
y = snd t
The pattern can be complex and we don’t want to unpack it many times.  
Moreover, the semantics says that it must be fully matched, so even if you just 
want ‘x’, you must check that the second component of the pair is indeed a 
singleton list.

So the “going via a tuple” part is nothing special about unboxed tuples – it 
simply holds for all lazy pattern bindings.


  1.  I don’t understand the details of Iavor’s proposal to add that “unlifted 
patterns are strict”, in addition to (1).  Do you mean “any sub-pattern of the 
LHS has an unlifted type”?  So
Just (# a,b #) = e
would be strict.   And even
MkT _ = e
would be strict if   data T = MkT (# Int,Int #)


  1.  Anything we do *must* scale to when we have user-defined unlifted data 
types (a current GHC Proposal)

TL;DR.  At the moment a change does not look attractive to me.  I could live 
with a warning for *outermost* unboxed tuples (or in general a constructor of 
an unlifted data type), suggesting to add a “!” or a “~” to make the intent 
clear.

Simon



From: ghc-devs  On Behalf Of Richard Eisenberg
Sent: 02 September 2020 14:47
To: Spiwack, Arnaud 
Cc: GHC developers 
Subject: Re: Implicit reboxing of unboxed tuple in let-patterns




On Sep 2, 2020, at 9:39 AM, Spiwack, Arnaud 
mailto:arnaud.spiw...@tweag.io>> wrote:

Ooh… pattern synonyms for unboxed tuple. I must confess that I don't know what 
the semantics of these ought to be. It does look like an interesting can of 
worms. How do they currently desugar?

Right now, there is one rule: if the type of any variable bound in the pattern 
is unlifted, then the pattern is an unlifter-var pattern and is strict. The 
pattern must be banged, unless the bound variable is not nested. This rule is 
consistent across all features.

This thread is suggesting to add a special case -- one that seems to match 
intuition, but it's still a special case. And my question is: should the 
special case be for unboxed tuples? or should the special case be for any 
pattern whose overall type is unlifted?

Richard
___
ghc-devs mailing list
ghc-devs@haskell.org
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs


Re: Implicit reboxing of unboxed tuple in let-patterns

2020-09-07 Thread Spiwack, Arnaud
On Fri, Sep 4, 2020 at 5:47 PM Iavor Diatchki 
wrote:

Yes
>
Interesting. Thanks.

Personally, I don’t really know how to resolve the tension between the
outer pattern saying: I *really* want to be lazy; and uniformity with the
unlifted-variable-binding case.

The point about b

b = let ~(MkX z) = undefined in ()

Is that it *cannot* do anything else than force the pattern. Because b is
an unlifted variable, it doesn’t contain a thunk. In other words, we can
read it as the pattern being lazy, but it being immediately forced. Pretty
much as in:

let (x,y) = undefined in x `seq` ()

My intuition would be that

let (x, (# #)) = (1, undefined) in ()

converges, while

let (x, (# #)) = (1, undefined) in x `seq` ()

diverges.

But I’m not exactly sure how to explain this rule succinctly. And I’m not
sure it would be quite as intuitive to anybody. For starters, it seems to
depart significantly from Iavor’s intuition.
___
ghc-devs mailing list
ghc-devs@haskell.org
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs


Re: Implicit reboxing of unboxed tuple in let-patterns

2020-09-03 Thread Domínguez , Facundo
> I guess a more explicit option would be to make it an error to use a lazy
pattern on an unlifted type, and require programmers to manually add the
`!` but I am not sure that gains much, and is more work in the compiler.

Not being used to deal with unlifted types, this would be my preferred
option. Having the meaning of let change depending on the levity of the
type is a good opportunity for confusion.

Cheers,
Facundo


On Thu, Sep 3, 2020 at 3:43 PM Iavor Diatchki 
wrote:

> Yeah, I think these are nice examples that illustrate some of the
> problems with the current behavior of GHC.   For example, I think it is
> weird that `b` non-terminates, but `c` does, because `z` is not used.  I
> would expect those to be equivalent.
>
> My preference would be to use the simple rule I mentioned before, but
> change how bang patterns work in pattern bindings.  In particular, I think
> writing a bang pattern should constitute a use of the banged value.  I
> think two equivalent ways to specify this is to say that a) writing a
> nested bang pattern implicitly adds bangs to the enclosing patterns, or I
> think equivalently b) writing `!p` is the same as writing `x@p` and
> adding `seq x` the same way we do for simple `!x = e` definitions
>
> With this interpretation, all but `e` would diverge, which matches my
> intuition of how unboxed types should work.
>
> -Iavor
>
>
> On Thu, Sep 3, 2020 at 11:02 AM Richard Eisenberg 
> wrote:
>
>>
>>
>> On Sep 3, 2020, at 1:51 PM, Iavor Diatchki 
>> wrote:
>>
>> How about the following rule:  unlifted patterns are always strict (i.e.,
>> you desugar them as if they had an explicit  `!`).   A pattern is
>> "unlifted" if the type it examines is unlifted.   Seems simple enough and,
>> I think, it would do what most folks would expect.
>>
>>
>> I don't think it's this simple. For example:
>>
>> > data X = MkX Int#
>> >
>> > a = let MkX 3# = undefined in ()
>> > b = let MkX z = undefined in ()
>> > c = let MkX _ = undefined in ()
>> > d = let MkX {} = undefined in ()
>> > e = let _ :: X = undefined in ()
>>
>> Which of these diverge? e definitely converges, as X is lifted. b
>> definitely diverges, because it binds z, a variable of an unlifted type, to
>> a component of a diverging computation.
>>
>> In GHC today, all the cases other than b converge.
>>
>> Iavor suggests that a should diverge: 3# is a pattern of an unlifted
>> type. What about c? What about d? Very unclear to me.
>>
>> Note that banging the pattern nested inside the MkX does not change the
>> behavior (in GHC today) for any of the cases where this makes sense to do
>> so.
>>
>> Richard
>>
>>
>> I guess a more explicit option would be to make it an error to use a lazy
>> pattern on an unlifted type, and require programmers to manually add the
>> `!` but I am not sure that gains much, and is more work in the compiler.
>>
>> -Iavor
>>
>> On Thu, Sep 3, 2020 at 10:38 AM Richard Eisenberg 
>> wrote:
>>
>>>
>>>
>>> On Sep 3, 2020, at 12:10 PM, Spiwack, Arnaud 
>>> wrote:
>>>
>>> This is all a tad tricky, I must say.
>>>
>>>
>>> ... which is one of the reasons I originally wanted one simple rule. I'm
>>> not now saying I was in the right, but it is an attractive resting point
>>> for this discussion.
>>>
>>> To be clear, I don't think there's going to be any concrete action here
>>> without a proposal, so perhaps once this thread finds a resting point
>>> different than the status quo, someone will have to write it up.
>>>
>>> Richard
>>> ___
>>> ghc-devs mailing list
>>> ghc-devs@haskell.org
>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
>>>
>>
>> ___
> ghc-devs mailing list
> ghc-devs@haskell.org
> http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
>
___
ghc-devs mailing list
ghc-devs@haskell.org
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs


Re: Implicit reboxing of unboxed tuple in let-patterns

2020-09-03 Thread Iavor Diatchki
Yeah, I think these are nice examples that illustrate some of the
problems with the current behavior of GHC.   For example, I think it is
weird that `b` non-terminates, but `c` does, because `z` is not used.  I
would expect those to be equivalent.

My preference would be to use the simple rule I mentioned before, but
change how bang patterns work in pattern bindings.  In particular, I think
writing a bang pattern should constitute a use of the banged value.  I
think two equivalent ways to specify this is to say that a) writing a
nested bang pattern implicitly adds bangs to the enclosing patterns, or I
think equivalently b) writing `!p` is the same as writing `x@p` and adding
`seq x` the same way we do for simple `!x = e` definitions

With this interpretation, all but `e` would diverge, which matches my
intuition of how unboxed types should work.

-Iavor


On Thu, Sep 3, 2020 at 11:02 AM Richard Eisenberg  wrote:

>
>
> On Sep 3, 2020, at 1:51 PM, Iavor Diatchki 
> wrote:
>
> How about the following rule:  unlifted patterns are always strict (i.e.,
> you desugar them as if they had an explicit  `!`).   A pattern is
> "unlifted" if the type it examines is unlifted.   Seems simple enough and,
> I think, it would do what most folks would expect.
>
>
> I don't think it's this simple. For example:
>
> > data X = MkX Int#
> >
> > a = let MkX 3# = undefined in ()
> > b = let MkX z = undefined in ()
> > c = let MkX _ = undefined in ()
> > d = let MkX {} = undefined in ()
> > e = let _ :: X = undefined in ()
>
> Which of these diverge? e definitely converges, as X is lifted. b
> definitely diverges, because it binds z, a variable of an unlifted type, to
> a component of a diverging computation.
>
> In GHC today, all the cases other than b converge.
>
> Iavor suggests that a should diverge: 3# is a pattern of an unlifted type.
> What about c? What about d? Very unclear to me.
>
> Note that banging the pattern nested inside the MkX does not change the
> behavior (in GHC today) for any of the cases where this makes sense to do
> so.
>
> Richard
>
>
> I guess a more explicit option would be to make it an error to use a lazy
> pattern on an unlifted type, and require programmers to manually add the
> `!` but I am not sure that gains much, and is more work in the compiler.
>
> -Iavor
>
> On Thu, Sep 3, 2020 at 10:38 AM Richard Eisenberg 
> wrote:
>
>>
>>
>> On Sep 3, 2020, at 12:10 PM, Spiwack, Arnaud 
>> wrote:
>>
>> This is all a tad tricky, I must say.
>>
>>
>> ... which is one of the reasons I originally wanted one simple rule. I'm
>> not now saying I was in the right, but it is an attractive resting point
>> for this discussion.
>>
>> To be clear, I don't think there's going to be any concrete action here
>> without a proposal, so perhaps once this thread finds a resting point
>> different than the status quo, someone will have to write it up.
>>
>> Richard
>> ___
>> ghc-devs mailing list
>> ghc-devs@haskell.org
>> http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
>>
>
>
___
ghc-devs mailing list
ghc-devs@haskell.org
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs


Re: Implicit reboxing of unboxed tuple in let-patterns

2020-09-03 Thread Richard Eisenberg


> On Sep 3, 2020, at 1:51 PM, Iavor Diatchki  wrote:
> 
> How about the following rule:  unlifted patterns are always strict (i.e., you 
> desugar them as if they had an explicit  `!`).   A pattern is "unlifted" if 
> the type it examines is unlifted.   Seems simple enough and, I think, it 
> would do what most folks would expect.  

I don't think it's this simple. For example:

> data X = MkX Int#
>
> a = let MkX 3# = undefined in ()
> b = let MkX z = undefined in ()
> c = let MkX _ = undefined in ()
> d = let MkX {} = undefined in ()
> e = let _ :: X = undefined in ()

Which of these diverge? e definitely converges, as X is lifted. b definitely 
diverges, because it binds z, a variable of an unlifted type, to a component of 
a diverging computation.

In GHC today, all the cases other than b converge.

Iavor suggests that a should diverge: 3# is a pattern of an unlifted type. What 
about c? What about d? Very unclear to me.

Note that banging the pattern nested inside the MkX does not change the 
behavior (in GHC today) for any of the cases where this makes sense to do so.

Richard

> 
> I guess a more explicit option would be to make it an error to use a lazy 
> pattern on an unlifted type, and require programmers to manually add the `!` 
> but I am not sure that gains much, and is more work in the compiler.
> 
> -Iavor
> 
> On Thu, Sep 3, 2020 at 10:38 AM Richard Eisenberg  > wrote:
> 
> 
>> On Sep 3, 2020, at 12:10 PM, Spiwack, Arnaud > > wrote:
>> 
>> This is all a tad tricky, I must say.
> 
> ... which is one of the reasons I originally wanted one simple rule. I'm not 
> now saying I was in the right, but it is an attractive resting point for this 
> discussion.
> 
> To be clear, I don't think there's going to be any concrete action here 
> without a proposal, so perhaps once this thread finds a resting point 
> different than the status quo, someone will have to write it up.
> 
> Richard
> ___
> ghc-devs mailing list
> ghc-devs@haskell.org 
> http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs 
> 

___
ghc-devs mailing list
ghc-devs@haskell.org
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs


Re: Implicit reboxing of unboxed tuple in let-patterns

2020-09-03 Thread Iavor Diatchki
How about the following rule:  unlifted patterns are always strict (i.e.,
you desugar them as if they had an explicit  `!`).   A pattern is
"unlifted" if the type it examines is unlifted.   Seems simple enough and,
I think, it would do what most folks would expect.

I guess a more explicit option would be to make it an error to use a lazy
pattern on an unlifted type, and require programmers to manually add the
`!` but I am not sure that gains much, and is more work in the compiler.

-Iavor

On Thu, Sep 3, 2020 at 10:38 AM Richard Eisenberg  wrote:

>
>
> On Sep 3, 2020, at 12:10 PM, Spiwack, Arnaud 
> wrote:
>
> This is all a tad tricky, I must say.
>
>
> ... which is one of the reasons I originally wanted one simple rule. I'm
> not now saying I was in the right, but it is an attractive resting point
> for this discussion.
>
> To be clear, I don't think there's going to be any concrete action here
> without a proposal, so perhaps once this thread finds a resting point
> different than the status quo, someone will have to write it up.
>
> Richard
> ___
> ghc-devs mailing list
> ghc-devs@haskell.org
> http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
>
___
ghc-devs mailing list
ghc-devs@haskell.org
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs


Re: Implicit reboxing of unboxed tuple in let-patterns

2020-09-03 Thread Richard Eisenberg


> On Sep 3, 2020, at 12:10 PM, Spiwack, Arnaud  wrote:
> 
> This is all a tad tricky, I must say.

... which is one of the reasons I originally wanted one simple rule. I'm not 
now saying I was in the right, but it is an attractive resting point for this 
discussion.

To be clear, I don't think there's going to be any concrete action here without 
a proposal, so perhaps once this thread finds a resting point different than 
the status quo, someone will have to write it up.

Richard___
ghc-devs mailing list
ghc-devs@haskell.org
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs


Re: Implicit reboxing of unboxed tuple in let-patterns

2020-09-03 Thread Spiwack, Arnaud
>
> Right now, there is one rule: if the type of any variable bound in the
>> pattern is unlifted, then the pattern is an unlifter-var pattern and is
>> strict.
>>
>
> I think the intuition I followed so far was "bindings with unlifted *RHS*
> are strict".
>

 This is a very different rule indeed! And one which gives a strict
semantic to the initial offender.

But there are holes in it: if I `let (x, y) = blah in …` and `x` is at an
unlifted type, the pattern _needs_ to be strict (this is solved by the
current rule as described by Richard) despite the rhs being at a lifted
type. That's because binding `x` forces the pattern anyway, by definition.
There are questions about nested patterns, as well. What about `let (U x,
y) = blah in …`, where `U` is some unlifted type. Is the nested `U x`
pattern strict? or is it lazy? There is no corresponding right-hand side.

This is all a tad tricky, I must say.
___
ghc-devs mailing list
ghc-devs@haskell.org
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs


Re: Implicit reboxing of unboxed tuple in let-patterns

2020-09-03 Thread Sebastian Graf
Hi,

Right now, there is one rule: if the type of any variable bound in the
> pattern is unlifted, then the pattern is an unlifter-var pattern and is
> strict.
>

I think the intuition I followed so far was "bindings with unlifted *RHS*
are strict".
So if I take a program in a strict language with Haskell syntax (Idris with
a different syntax, not like -XStrict) and replace all types with their
unlifted counterparts (which should be possible once we have
-XUnliftedDatatypes), then I get exactly the same semantics in GHC Haskell.
I find this property very useful.
As a special case that means that any binders of unlifted type are bound
strictly, if only for uniformity with simple variable bindings. I think my
intuition is different to Richard's rule only for the "unlifted constructor
match with nested lifted-only variable matches" case.

Sebastian

Am Do., 3. Sept. 2020 um 14:48 Uhr schrieb Spiwack, Arnaud <
arnaud.spiw...@tweag.io>:

> This thread is suggesting to add a special case -- one that seems to match
>> intuition, but it's still a special case. And my question is: should the
>> special case be for unboxed tuples? or should the special case be for any
>> pattern whose overall type is unlifted?
>>
>
> My intuition would be: for all unlifted types. I'd submit that the
> distinction between lazy and strict pattern-matching doesn't really make a
> ton of sense for unlifted types. To implement lazy pattern-matching on an
> unlifted type, one has to actually indirect through another type, which I
> find deeply suspicious.
>
> That being said
>
> Right now, there is one rule: if the type of any variable bound in the
>> pattern is unlifted, then the pattern is an unlifter-var pattern and is
>> strict. The pattern must be banged, unless the bound variable is not
>> nested. This rule is consistent across all features.
>>
>
>  I realise that there are a lot of subtil details to get right to specify
> pattern-matching. Or at the very least, that it's difficult to come up with
> a straightforward specification which is as clear as the one above.
>
> I'm wondering though: have there been discussions which led to the above
> rule, or did it just come to be, mostly informally? (and if there have been
> explicit discussions, are they recorded somewhere?)
> ___
> ghc-devs mailing list
> ghc-devs@haskell.org
> http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
>
___
ghc-devs mailing list
ghc-devs@haskell.org
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs


Re: Implicit reboxing of unboxed tuple in let-patterns

2020-09-03 Thread Spiwack, Arnaud
>
> This thread is suggesting to add a special case -- one that seems to match
> intuition, but it's still a special case. And my question is: should the
> special case be for unboxed tuples? or should the special case be for any
> pattern whose overall type is unlifted?
>

My intuition would be: for all unlifted types. I'd submit that the
distinction between lazy and strict pattern-matching doesn't really make a
ton of sense for unlifted types. To implement lazy pattern-matching on an
unlifted type, one has to actually indirect through another type, which I
find deeply suspicious.

That being said

Right now, there is one rule: if the type of any variable bound in the
> pattern is unlifted, then the pattern is an unlifter-var pattern and is
> strict. The pattern must be banged, unless the bound variable is not
> nested. This rule is consistent across all features.
>

 I realise that there are a lot of subtil details to get right to specify
pattern-matching. Or at the very least, that it's difficult to come up with
a straightforward specification which is as clear as the one above.

I'm wondering though: have there been discussions which led to the above
rule, or did it just come to be, mostly informally? (and if there have been
explicit discussions, are they recorded somewhere?)
___
ghc-devs mailing list
ghc-devs@haskell.org
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs


Re: Implicit reboxing of unboxed tuple in let-patterns

2020-09-02 Thread Richard Eisenberg


> On Sep 2, 2020, at 9:39 AM, Spiwack, Arnaud  wrote:
> 
> Ooh… pattern synonyms for unboxed tuple. I must confess that I don't know 
> what the semantics of these ought to be. It does look like an interesting can 
> of worms. How do they currently desugar?

Right now, there is one rule: if the type of any variable bound in the pattern 
is unlifted, then the pattern is an unlifter-var pattern and is strict. The 
pattern must be banged, unless the bound variable is not nested. This rule is 
consistent across all features.

This thread is suggesting to add a special case -- one that seems to match 
intuition, but it's still a special case. And my question is: should the 
special case be for unboxed tuples? or should the special case be for any 
pattern whose overall type is unlifted?

Richard___
ghc-devs mailing list
ghc-devs@haskell.org
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs


Re: Implicit reboxing of unboxed tuple in let-patterns

2020-09-02 Thread Spiwack, Arnaud
> I admit I don't feel as strongly any more. My argument in that thread was
> from the standpoint of a language designer: there is really no reason, a
> priori, for an unboxed-tuple binding to be strict. What controls strictness
> is whether the bound variables are of unlifted type. However, I'm currently
> in more sympathy with language users, who (for whatever reason) seem to
> think that bindings with #s in them should be strict. (I have this
> intuition myself, even though it's not quite warranted on technical
> grounds.)
>

A middle ground could be to not allow unbanged patterns for unboxed tuples.
Since they currently exist, we could also simply emit a warning, saying:
“this is probably not what you want, do add an exclamation mark”.


> What do we think of
>
> pattern Unl x y = (# x, y #)
>
> ex1, ex2 :: ()
> ex1 = let Unl x y = Unl undefined undefined in ()
> ex2 = let Unl x y = undefined in ()
>
>
> ? Today, both ex1 and ex2 evaluate to (). If we were to change the
> specification here, would we consider any unlifted-type pattern (where the
> type of the pattern itself is unlifted, independent of the type of any of
> its bound variables) to be banged? Or would it be a super-special case for
> unboxed tuples?
>

Ooh… pattern synonyms for unboxed tuple. I must confess that I don't know
what the semantics of these ought to be. It does look like an interesting
can of worms. How do they currently desugar?
___
ghc-devs mailing list
ghc-devs@haskell.org
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs


Re: Implicit reboxing of unboxed tuple in let-patterns

2020-08-31 Thread Richard Eisenberg


> On Aug 31, 2020, at 10:34 AM, Spiwack, Arnaud  wrote:
> 
> That being said, Richard seemed to feel rather strongly about this one. 
> Richard, do you still agree with your then position that let (#x, y#) = … 
> being a lazy pattern (hence implicitly boxes the pair) is the right semantics?

I admit I don't feel as strongly any more. My argument in that thread was from 
the standpoint of a language designer: there is really no reason, a priori, for 
an unboxed-tuple binding to be strict. What controls strictness is whether the 
bound variables are of unlifted type. However, I'm currently in more sympathy 
with language users, who (for whatever reason) seem to think that bindings with 
#s in them should be strict. (I have this intuition myself, even though it's 
not quite warranted on technical grounds.)

What do we think of

> pattern Unl x y = (# x, y #)
> 
> ex1, ex2 :: ()
> ex1 = let Unl x y = Unl undefined undefined in ()
> ex2 = let Unl x y = undefined in ()


? Today, both ex1 and ex2 evaluate to (). If we were to change the 
specification here, would we consider any unlifted-type pattern (where the type 
of the pattern itself is unlifted, independent of the type of any of its bound 
variables) to be banged? Or would it be a super-special case for unboxed tuples?

Richard___
ghc-devs mailing list
ghc-devs@haskell.org
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs


Re: Implicit reboxing of unboxed tuple in let-patterns

2020-08-31 Thread John Cotton Ericson
I haven't used unboxed tuples enough to perhaps feel the pain, but on 
paper the current design makes sense to me. The laziness of the binding 
is suppose to have to do with the runtime rep of the binding itself, not 
any enclosing pattern.


For example take

    {-# LANGUAGE ScopedTypeVariables #-}
    {-# LANGUAGE MagicHash #-}

    import GHC.Base

    data Foo = Foo Int# Int#

    main = pure ()
    where Foo x y = Foo undefined undefined

This program will fail even though x and y are unused.

While this principle may not match how this stuff is used in practice, 
the alternative of making the strictness of the bindings depend on more 
than their runtime reps seems less-local / more ad-hoc to me.


John

On 8/31/20 10:34 AM, Spiwack, Arnaud wrote:


I’ve been pointed to 
https://github.com/ghc-proposals/ghc-proposals/pull/35 where this was 
debated a few years ago. With much of the same arguments as today.


Simon Marlow said

making an unboxed tuple binding lazy by default seems to be
intuitively the wrong choice. I guarantee I would get tripped up
by this! Giving unboxed tuples an implicit bang seems reasonable
to me.

I can share that I got tripped by it. And so were other members of my 
team.


That being said, Richard seemed to feel rather strongly about this 
one. Richard, do you still agree with your then position that |let 
(#x, y#) = …| being a lazy pattern (hence implicitly boxes the pair) 
is the right semantics?



On Fri, Aug 28, 2020 at 8:26 PM chessai > wrote:


Arnaud,

I have dealt with this in the past and find the laziness extremely
counterintuitive and never wanted. Every time I have let-bound an
unboxed tuple, I have never wanted that boxing to occur. Perhaps
there is a good reason this is the case but I wish it would change.

On Fri, Aug 28, 2020, 08:26 Spiwack, Arnaud
mailto:arnaud.spiw...@tweag.io>> wrote:

Hi Carter,

We are using |let !(#x,y#) = …| actually. Having the strict
behaviour is not particularly difficult. You can even use
|case … of (#x, y#) ->…| directly, it’s not too bad. My
complaint, as it were, is solely about the potential for mistakes.


On Fri, Aug 28, 2020 at 3:20 PM Carter Schonwald
mailto:carter.schonw...@gmail.com>> wrote:

Have you tried using do notation for bindings you want to
keep strict, with Eg the identity monad?  That doesn’t
address  the design critique but gives you a path forward ?

I do agree that the semantics / default recursivity Of let
bindings  can be inappropriate for non recursive code ,
but would any other non uniform semantics or optimization
be safe?

On Fri, Aug 28, 2020 at 9:05 AM Spiwack, Arnaud
mailto:arnaud.spiw...@tweag.io>>
wrote:

Dear all,



I discovered the hard way, yesterday, that lazy let
pattern
matching is allowed on unboxed tuples. And that it
implicitly reboxes
the pattern.



Here is how the manual describes it, from the relevant
section

:





You can have an unboxed tuple in a pattern
binding, thus



|f x = let (# p,q #) = h x in ..body.. |



If the types of |p| and |q| are not unboxed, the
resulting binding is lazy like any other Haskell
pattern binding. The above example desugars like this:



|f x = let t = case h x of { (# p,q #) -> (p,q) }
p = fst t q = snd t in ..body.. |



Indeed, the bindings can even be recursive.





Notice how |h x| is lazily bound, hence won’t
necessarily be run when
|body| is forced. as opposed to if I had written, for
instance,



|let u = hx in ..body.. |



My question is: are we happy with this? I did find
this extremely
surprising. If I’m using unboxed tuples, it’s because
I want to
guarantee to myself a strict, unboxed behaviour. But a
very subtle
syntactic detail seems to break this expectation for
me. My
expectation would be that I would need to explicitly
rebox things
before they get lazy again.



I find that this behaviour invites trouble. But you
may disagree. Let
me know!





___

ghc-devs mailing list

  

Re: Implicit reboxing of unboxed tuple in let-patterns

2020-08-28 Thread Spiwack, Arnaud
Hi Carter,

We are using let !(#x,y#) = … actually. Having the strict behaviour is not
particularly difficult. You can even use case … of (#x, y#) ->… directly,
it’s not too bad. My complaint, as it were, is solely about the potential
for mistakes.

On Fri, Aug 28, 2020 at 3:20 PM Carter Schonwald 
wrote:

> Have you tried using do notation for bindings you want to keep strict,
> with Eg the identity monad?  That doesn’t address  the design critique but
> gives you a path forward ?
>
> I do agree that the semantics / default recursivity Of let bindings  can
> be inappropriate for non recursive code , but would any other non uniform
> semantics or optimization be safe?
>
> On Fri, Aug 28, 2020 at 9:05 AM Spiwack, Arnaud 
> wrote:
>
>> Dear all,
>>
>>
>> I discovered the hard way, yesterday, that lazy let pattern
>> matching is allowed on unboxed tuples. And that it implicitly reboxes
>> the pattern.
>>
>>
>> Here is how the manual describes it, from the relevant section
>> 
>> :
>>
>>
>>
>>
>> You can have an unboxed tuple in a pattern binding, thus
>>
>>
>> f x = let (# p,q #) = h x in ..body..
>>
>>
>>
>> If the types of p and q are not unboxed, the resulting binding is lazy
>> like any other Haskell pattern binding. The above example desugars like
>> this:
>>
>>
>> f x = let t = case h x of { (# p,q #) -> (p,q) }
>>
>>   p = fst t
>>
>>   q = snd t
>>
>>   in ..body..
>>
>>
>>
>> Indeed, the bindings can even be recursive.
>>
>>
>>
>>
>> Notice how h x is lazily bound, hence won’t necessarily be run when
>> body is forced. as opposed to if I had written, for instance,
>>
>>
>> let u = hx
>>
>> in ..body..
>>
>>
>>
>> My question is: are we happy with this? I did find this extremely
>> surprising. If I’m using unboxed tuples, it’s because I want to
>> guarantee to myself a strict, unboxed behaviour. But a very subtle
>> syntactic detail seems to break this expectation for me. My
>> expectation would be that I would need to explicitly rebox things
>> before they get lazy again.
>>
>>
>> I find that this behaviour invites trouble. But you may disagree. Let
>> me know!
>>
>>
>>
>>
>> ___
>>
>> ghc-devs mailing list
>>
>> ghc-devs@haskell.org
>>
>> http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
>>
>>
___
ghc-devs mailing list
ghc-devs@haskell.org
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs


Re: Implicit reboxing of unboxed tuple in let-patterns

2020-08-28 Thread Carter Schonwald
Have you tried using do notation for bindings you want to keep strict, with
Eg the identity monad?  That doesn’t address  the design critique but gives
you a path forward ?

I do agree that the semantics / default recursivity Of let bindings  can be
inappropriate for non recursive code , but would any other non uniform
semantics or optimization be safe?

On Fri, Aug 28, 2020 at 9:05 AM Spiwack, Arnaud 
wrote:

> Dear all,
>
>
> I discovered the hard way, yesterday, that lazy let pattern
> matching is allowed on unboxed tuples. And that it implicitly reboxes
> the pattern.
>
>
> Here is how the manual describes it, from the relevant section
> 
> :
>
>
>
>
> You can have an unboxed tuple in a pattern binding, thus
>
>
> f x = let (# p,q #) = h x in ..body..
>
>
>
> If the types of p and q are not unboxed, the resulting binding is lazy
> like any other Haskell pattern binding. The above example desugars like
> this:
>
>
> f x = let t = case h x of { (# p,q #) -> (p,q) }
>
>   p = fst t
>
>   q = snd t
>
>   in ..body..
>
>
>
> Indeed, the bindings can even be recursive.
>
>
>
>
> Notice how h x is lazily bound, hence won’t necessarily be run when
> body is forced. as opposed to if I had written, for instance,
>
>
> let u = hx
>
> in ..body..
>
>
>
> My question is: are we happy with this? I did find this extremely
> surprising. If I’m using unboxed tuples, it’s because I want to
> guarantee to myself a strict, unboxed behaviour. But a very subtle
> syntactic detail seems to break this expectation for me. My
> expectation would be that I would need to explicitly rebox things
> before they get lazy again.
>
>
> I find that this behaviour invites trouble. But you may disagree. Let
> me know!
>
>
>
>
> ___
>
> ghc-devs mailing list
>
> ghc-devs@haskell.org
>
> http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
>
>
___
ghc-devs mailing list
ghc-devs@haskell.org
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs