# -XStrict: Why some binders are not made strict?

 Classic List Threaded
17 messages
Reply | Threaded
Open this post in threaded view
|

## -XStrict: Why some binders are not made strict?

 Let's say I have this code:     zip :: [a] -> [b] -> [(a, b)]     zip [] [] = []     zip (x : xs) (y : ys) = (x, y) : zip xs ys With -XStrict 'x', 'xs', 'y' and 'ys' don't become strict. I'm wondering about the motivation behind this, I found this interesting. I always thought -XStrict gives me this guarantee: If I'm using an already-defined variable(bound by a let or pattern matching) in an expression, I can be sure that the variable won't be bottom in that expression, because it would be `seq`d before the expression is evaluated. So if I have     case ... of         D x y -> or     let x = ...         y = ...      in In both cases I was thinking that in 'x' and 'y' can't be bottom(with -XStrict). This would make -XStrict programs evaluate like they would in a call-by-value language(even though in the RTS level thunks will be built). Variables can't range over computations; all binders evaluated strictly etc. Can anyone tell me about the motivation behind this decision? I think the wiki page actually conflicts with itself. It says "... bindings to be strict by default" but then in "case expressions" sections says     case x of (a,b) -> rhs     is interpreted as     case x of !(a,b) -> rhs Here bindings 'a' and 'b' are not made strict. I'd expect something like:     case x of (!a,!b) -> rhs (Which seems to be invalid Haskell, but same effect could be achieved with `seq a (seq b rhs)`) Thanks.. (I also realized that the wiki page doesn't mention bindings in do syntax, is it because this case is implied by "function definitions"? That is, bangs are added after do syntax is desugared and so they become strict?) _______________________________________________ ghc-devs mailing list [hidden email] http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
Reply | Threaded
Open this post in threaded view
|

## Re: -XStrict: Why some binders are not made strict?

 On Mon, Dec 7, 2015 at 8:40 PM, Ömer Sinan Ağacan wrote:With -XStrict 'x', 'xs', 'y' and 'ys' don't become strict. I'm wondering about the motivation behind this, I found this interesting. I always thought -XStrict gives me this guarantee: If I'm using an already-defined variable(bound by a let or pattern matching) in an expression, I can be sure that the variable won't be bottom in that expression, because it would be `seq`d before the expression is evaluated.Aren't those already guaranteed to be strict because of pattern matching? Try it again with irrefutable patterns.-- brandon s allbery kf8nh                               sine nomine associatesunix, openafs, kerberos, infrastructure, xmonad        http://sinenomine.net _______________________________________________ ghc-devs mailing list [hidden email] http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
Reply | Threaded
Open this post in threaded view
|

## Re: -XStrict: Why some binders are not made strict?

 > Aren't those already guaranteed to be strict because of pattern matching? Try > it again with irrefutable patterns. But pattern matching only forces the evaluation up to the pattern that is matched. We need another pattern matching(or seq etc.) on x, y, xs and ys here. If you look at the generated Core you'll see it more clearly I think(you'll see that no pattern matching on x y xs and ys are done in Core). 2015-12-07 20:43 GMT-05:00 Brandon Allbery <[hidden email]>: > On Mon, Dec 7, 2015 at 8:40 PM, Ömer Sinan Ağacan <[hidden email]> > wrote: >> >> With -XStrict 'x', 'xs', 'y' and 'ys' don't become strict. I'm wondering >> about >> the motivation behind this, I found this interesting. I always thought >> -XStrict >> gives me this guarantee: If I'm using an already-defined variable(bound by >> a >> let or pattern matching) in an expression, I can be sure that the variable >> won't be bottom in that expression, because it would be `seq`d before the >> expression is evaluated. > > > Aren't those already guaranteed to be strict because of pattern matching? > Try it again with irrefutable patterns. > > -- > brandon s allbery kf8nh                               sine nomine associates > [hidden email]                                  [hidden email] > unix, openafs, kerberos, infrastructure, xmonad        http://sinenomine.net_______________________________________________ ghc-devs mailing list [hidden email] http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
Reply | Threaded
Open this post in threaded view
|

## RE: -XStrict: Why some binders are not made strict?

 In reply to this post by Ömer Sinan Ağacan Adam, Johan, Looking at the user manual http://downloads.haskell.org/~ghc/master/users-guide/glasgow_exts.html#strict-haskell, and indeed the wiki page https://ghc.haskell.org/trac/ghc/wiki/StrictPragmait's not really clear whether the sub-components of a pattern are strict.  That is, is the second equation of zip strict in x, and xs?   (Supposing for now that the list data structure is lazy).  The manual doesn't say one way or the other. What's the answer?  And could the user manual please say? Thanks Simon | -----Original Message----- | From: ghc-devs [mailto:[hidden email]] On Behalf Of Ömer | Sinan Agacan | Sent: 08 December 2015 01:41 | To: ghc-devs <[hidden email]> | Subject: -XStrict: Why some binders are not made strict? | | Let's say I have this code: | |     zip :: [a] -> [b] -> [(a, b)] |     zip [] [] = [] |     zip (x : xs) (y : ys) = (x, y) : zip xs ys | | With -XStrict 'x', 'xs', 'y' and 'ys' don't become strict. I'm wondering | about | the motivation behind this, I found this interesting. I always thought - | XStrict | gives me this guarantee: If I'm using an already-defined variable(bound by | a | let or pattern matching) in an expression, I can be sure that the variable | won't be bottom in that expression, because it would be `seq`d before the | expression is evaluated. | | So if I have | |     case ... of |         D x y -> | | or | |     let x = ... |         y = ... |      in | | In both cases I was thinking that in 'x' and 'y' can't be | bottom(with | -XStrict). This would make -XStrict programs evaluate like they would in a | call-by-value language(even though in the RTS level thunks will be built). | Variables can't range over computations; all binders evaluated strictly | etc. | | Can anyone tell me about the motivation behind this decision? | | I think the wiki page actually conflicts with itself. It says "... | bindings to be | strict by default" but then in "case expressions" sections says | |     case x of (a,b) -> rhs | |     is interpreted as | |     case x of !(a,b) -> rhs | | Here bindings 'a' and 'b' are not made strict. I'd expect something like: | |     case x of (!a,!b) -> rhs | | (Which seems to be invalid Haskell, but same effect could be achieved with | `seq | a (seq b rhs)`) | | Thanks.. | | (I also realized that the wiki page doesn't mention bindings in do syntax, | is | it because this case is implied by "function definitions"? That is, bangs | are | added after do syntax is desugared and so they become strict?) | _______________________________________________ | ghc-devs mailing list | [hidden email] | https://na01.safelinks.protection.outlook.com/?url=http%3a%2f%2fmail.haske| ll.org%2fcgi-bin%2fmailman%2flistinfo%2fghc- | devs&data=01%7c01%7csimonpj%40064d.mgd.microsoft.com%7cbc68c0830f574466efd | 308d2ff70aba9%7c72f988bf86f141af91ab2d7cd011db47%7c1&sdata=c2VBbt%2f%2fR2c | yFecGEuQotO%2bV71VSbpmWnZJyV9d8KRk%3d _______________________________________________ ghc-devs mailing list [hidden email] http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
Reply | Threaded
Open this post in threaded view
|

## Re: -XStrict: Why some binders are not made strict?

 I'm snowed under but I promise I will try to reply soon! To think about in the mean time: what do existing strict languages with pattern matching do?On Tue, Dec 8, 2015 at 3:42 PM, Simon Peyton Jones wrote:Adam, Johan, Looking at the user manual http://downloads.haskell.org/~ghc/master/users-guide/glasgow_exts.html#strict-haskell, and indeed the wiki page https://ghc.haskell.org/trac/ghc/wiki/StrictPragma it's not really clear whether the sub-components of a pattern are strict.  That is, is the second equation of zip strict in x, and xs?   (Supposing for now that the list data structure is lazy).  The manual doesn't say one way or the other. What's the answer?  And could the user manual please say? Thanks Simon | -----Original Message----- | From: ghc-devs [mailto:[hidden email]] On Behalf Of Ömer | Sinan Agacan | Sent: 08 December 2015 01:41 | To: ghc-devs <[hidden email]> | Subject: -XStrict: Why some binders are not made strict? | | Let's say I have this code: | |     zip :: [a] -> [b] -> [(a, b)] |     zip [] [] = [] |     zip (x : xs) (y : ys) = (x, y) : zip xs ys | | With -XStrict 'x', 'xs', 'y' and 'ys' don't become strict. I'm wondering | about | the motivation behind this, I found this interesting. I always thought - | XStrict | gives me this guarantee: If I'm using an already-defined variable(bound by | a | let or pattern matching) in an expression, I can be sure that the variable | won't be bottom in that expression, because it would be `seq`d before the | expression is evaluated. | | So if I have | |     case ... of |         D x y -> | | or | |     let x = ... |         y = ... |      in | | In both cases I was thinking that in 'x' and 'y' can't be | bottom(with | -XStrict). This would make -XStrict programs evaluate like they would in a | call-by-value language(even though in the RTS level thunks will be built). | Variables can't range over computations; all binders evaluated strictly | etc. | | Can anyone tell me about the motivation behind this decision? | | I think the wiki page actually conflicts with itself. It says "... | bindings to be | strict by default" but then in "case expressions" sections says | |     case x of (a,b) -> rhs | |     is interpreted as | |     case x of !(a,b) -> rhs | | Here bindings 'a' and 'b' are not made strict. I'd expect something like: | |     case x of (!a,!b) -> rhs | | (Which seems to be invalid Haskell, but same effect could be achieved with | `seq | a (seq b rhs)`) | | Thanks.. | | (I also realized that the wiki page doesn't mention bindings in do syntax, | is | it because this case is implied by "function definitions"? That is, bangs | are | added after do syntax is desugared and so they become strict?) | _______________________________________________ | ghc-devs mailing list | [hidden email] | https://na01.safelinks.protection.outlook.com/?url=http%3a%2f%2fmail.haske | ll.org%2fcgi-bin%2fmailman%2flistinfo%2fghc- | devs&data=01%7c01%7csimonpj%40064d.mgd.microsoft.com%7cbc68c0830f574466efd | 308d2ff70aba9%7c72f988bf86f141af91ab2d7cd011db47%7c1&sdata=c2VBbt%2f%2fR2c | yFecGEuQotO%2bV71VSbpmWnZJyV9d8KRk%3d _______________________________________________ ghc-devs mailing list [hidden email] http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
Reply | Threaded
Open this post in threaded view
|

## Re: -XStrict: Why some binders are not made strict?

 When implementing I took this:   > Notice that we do not put bangs on nested patterns. For example >   let (p,q) = if flob then (undefined, undefined) else (True, False) >    in ... > will behave like >   let !(p,q) = if flob then (undefined, undefined) else (True, False) >   in ...   (from the spec) and applied it to all bindings, but I don't know if this is the best implementation.   Cheers, Adam      On Thu, 10 Dec 2015, at 03:34 PM, Johan Tibell wrote: I'm snowed under but I promise I will try to reply soon! To think about in the mean time: what do existing strict languages with pattern matching do?   On Tue, Dec 8, 2015 at 3:42 PM, Simon Peyton Jones wrote: Adam, Johan,   Looking at the user manual and indeed the wiki page it's not really clear whether the sub-components of a pattern are strict.  That is, is the second equation of zip strict in x, and xs?   (Supposing for now that the list data structure is lazy).  The manual doesn't say one way or the other.   What's the answer?  And could the user manual please say?   Thanks   Simon   | -----Original Message----- | From: ghc-devs [mailto:[hidden email]] On Behalf Of Ömer | Sinan Agacan | Sent: 08 December 2015 01:41 | To: ghc-devs <[hidden email]> | Subject: -XStrict: Why some binders are not made strict? | | Let's say I have this code: | |     zip :: [a] -> [b] -> [(a, b)] |     zip [] [] = [] |     zip (x : xs) (y : ys) = (x, y) : zip xs ys | | With -XStrict 'x', 'xs', 'y' and 'ys' don't become strict. I'm wondering | about | the motivation behind this, I found this interesting. I always thought - | XStrict | gives me this guarantee: If I'm using an already-defined variable(bound by | a | let or pattern matching) in an expression, I can be sure that the variable | won't be bottom in that expression, because it would be `seq`d before the | expression is evaluated. | | So if I have | |     case ... of |         D x y -> | | or | |     let x = ... |         y = ... |      in | | In both cases I was thinking that in 'x' and 'y' can't be | bottom(with | -XStrict). This would make -XStrict programs evaluate like they would in a | call-by-value language(even though in the RTS level thunks will be built). | Variables can't range over computations; all binders evaluated strictly | etc. | | Can anyone tell me about the motivation behind this decision? | | I think the wiki page actually conflicts with itself. It says "... | bindings to be | strict by default" but then in "case expressions" sections says | |     case x of (a,b) -> rhs | |     is interpreted as | |     case x of !(a,b) -> rhs | | Here bindings 'a' and 'b' are not made strict. I'd expect something like: | |     case x of (!a,!b) -> rhs | | (Which seems to be invalid Haskell, but same effect could be achieved with | `seq | a (seq b rhs)`) | | Thanks.. | | (I also realized that the wiki page doesn't mention bindings in do syntax, | is | it because this case is implied by "function definitions"? That is, bangs | are | added after do syntax is desugared and so they become strict?) | _______________________________________________ | ghc-devs mailing list | ll.org%2fcgi-bin%2fmailman%2flistinfo%2fghc- | devs&data=01%7c01%7csimonpj%40064d.mgd.microsoft.com%7cbc68c0830f574466efd | 308d2ff70aba9%7c72f988bf86f141af91ab2d7cd011db47%7c1&sdata=c2VBbt%2f%2fR2c | yFecGEuQotO%2bV71VSbpmWnZJyV9d8KRk%3d   _______________________________________________ ghc-devs mailing list [hidden email] http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
Reply | Threaded
Open this post in threaded view
|

## Re: -XStrict: Why some binders are not made strict?

 In reply to this post by Johan Tibell-2 On 12/10/2015 04:34 PM, Johan Tibell wrote: > I'm snowed under but I promise I will try to reply soon! To think about > in the mean time: what do existing strict languages with pattern > matching do? Well, strict languages do not have lazy data to force to begin with, do they? Personally, I find the simple intuition of "all patterns are strict by default" rather appealing. E.g. I wouldn't expect the expressions   let (v1,v2) = a in f v2 and   let (v1,v2) = a; v3 = v2 in f v3 to have different semantics. If we decide to adopt this semantics, we need to address the meaning of the pattern   ~(v1, v2) under -XStrict. Intuitively, ~ should propagate to the subpatterns. An alternative is to disallow this pattern under -XStrict and require writing all ~s explicitly, which may get tedious:   ~(~v1, ~v2)   ~(~v1, ~(~v2, ~v3))   etc. We also need to ensure the consistency between this extension and the unlifted data types proposal [1], given their similarity. Interestingly, I don't see constructor patterns explained there either. [1]: https://ghc.haskell.org/trac/ghc/wiki/UnliftedDataTypes#Dynamicsemanticsofunliftedtypes_______________________________________________ ghc-devs mailing list [hidden email] http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs signature.asc (836 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

## Re: -XStrict: Why some binders are not made strict?

 I believe Scala has optional lazy values, but you could also consider in strict languages if you do manual thunking.If we force strictness all the way down it's not really call-by-value either, because the caller doesn't know what to evaluate (I think).In addition, making pattern matching strict in this way makes it hard to mix and match strict and lazy data types (e.g. Maybe), because using a lazy data type from another module will make it appear strict in your code (hurting modularity).On Fri, Dec 11, 2015 at 7:54 AM, Roman Cheplyaka wrote:On 12/10/2015 04:34 PM, Johan Tibell wrote: > I'm snowed under but I promise I will try to reply soon! To think about > in the mean time: what do existing strict languages with pattern > matching do? Well, strict languages do not have lazy data to force to begin with, do they? Personally, I find the simple intuition of "all patterns are strict by default" rather appealing. E.g. I wouldn't expect the expressions   let (v1,v2) = a in f v2 and   let (v1,v2) = a; v3 = v2 in f v3 to have different semantics. If we decide to adopt this semantics, we need to address the meaning of the pattern   ~(v1, v2) under -XStrict. Intuitively, ~ should propagate to the subpatterns. An alternative is to disallow this pattern under -XStrict and require writing all ~s explicitly, which may get tedious:   ~(~v1, ~v2)   ~(~v1, ~(~v2, ~v3))   etc. We also need to ensure the consistency between this extension and the unlifted data types proposal [1], given their similarity. Interestingly, I don't see constructor patterns explained there either. [1]: https://ghc.haskell.org/trac/ghc/wiki/UnliftedDataTypes#Dynamicsemanticsofunliftedtypes _______________________________________________ ghc-devs mailing list [hidden email] http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs _______________________________________________ ghc-devs mailing list [hidden email] http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
Reply | Threaded
Open this post in threaded view
|

## Re: -XStrict: Why some binders are not made strict?

 On 12/11/2015 02:21 PM, Johan Tibell wrote: > If we force strictness all the way down it's not really call-by-value > either, because the caller doesn't know what to evaluate (I think). Not sure what you mean here. > In addition, making pattern matching strict in this way makes it hard to > mix and match strict and lazy data types (e.g. Maybe), because using a > lazy data type from another module will make it appear strict in your > code (hurting modularity). I don't think this is a case about modularity. A lazy Maybe value defined in a lazy module remains lazy; and you can pass it to lazy functions without forcing it. Only when you pattern match on it *in the strict module*, the evaluation happens. As I said, I prefer this semantics mainly because it's easier to explain: all variables (and underscores) bound in a strict module refer to WHNF values. Do you have a similarly simple explanation for the semantics you're suggesting? Roman _______________________________________________ ghc-devs mailing list [hidden email] http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs signature.asc (836 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

## Re: -XStrict: Why some binders are not made strict?

 I agree with Roman here. Probably another reason for making every binding strict is this: (sorry if this is mentioned) Suppose I imported `data D = D ...` from another library and I'm in -XStrict. In this code:     case ... of       D b1 b2 ... -> I should be able to assume that b1, b2 ... etc. are all strict(that is, WHNF in ) becuase I'm in -XStrict. This also makes the behavior more consistent, I think. 2015-12-11 7:57 GMT-05:00 Roman Cheplyaka <[hidden email]>: > On 12/11/2015 02:21 PM, Johan Tibell wrote: >> If we force strictness all the way down it's not really call-by-value >> either, because the caller doesn't know what to evaluate (I think). > > Not sure what you mean here. > >> In addition, making pattern matching strict in this way makes it hard to >> mix and match strict and lazy data types (e.g. Maybe), because using a >> lazy data type from another module will make it appear strict in your >> code (hurting modularity). > > I don't think this is a case about modularity. A lazy Maybe value > defined in a lazy module remains lazy; and you can pass it to lazy > functions without forcing it. Only when you pattern match on it *in the > strict module*, the evaluation happens. > > As I said, I prefer this semantics mainly because it's easier to > explain: all variables (and underscores) bound in a strict module refer > to WHNF values. Do you have a similarly simple explanation for the > semantics you're suggesting? > > Roman > > > _______________________________________________ > ghc-devs mailing list > [hidden email] > http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs> _______________________________________________ ghc-devs mailing list [hidden email] http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
Reply | Threaded
Open this post in threaded view
|

## RE: -XStrict: Why some binders are not made strict?

 In reply to this post by Roman Cheplyaka-2 | As I said, I prefer this semantics mainly because it's easier to | explain: all variables (and underscores) bound in a strict module refer | to WHNF values. Do you have a similarly simple explanation for the | semantics you're suggesting? Here's one, which is roughly what the current implementation does (modulo bugs): * Code compiled under -XStrict constructs no thunks. So consider         module M1 where data T = C Int Int         module M2 where f n = C (n+1) (n-1)         module M3 where g x = let C y z = f x in ... Look at M3.  Usually we'd get a thunk for (f 4), but not with -XStrict.  But even with -XStrict in M3, y,z might be bound to thunks.   If you compile M2 with -XStrict, function f won't build thunks for (n+1), (n-1) but will evaluate them instead. If you compile M1 with StrictData, then C is made strict, so again M2 will build no thunks even if M2 was compiled without -XStrict. I quite like this design.  It's not clear to me that anything useful is gained by forcing y and z in M3 before evaluating the body "...". So Roman's design makes sense, but so does the implemented design (modulo any bugs).  The trouble is that the implemented design is not well described. Simon | -----Original Message----- | From: ghc-devs [mailto:[hidden email]] On Behalf Of Roman | Cheplyaka | Sent: 11 December 2015 12:57 | To: Johan Tibell <[hidden email]> | Cc: [hidden email] | Subject: Re: -XStrict: Why some binders are not made strict? | | On 12/11/2015 02:21 PM, Johan Tibell wrote: | > If we force strictness all the way down it's not really call-by-value | > either, because the caller doesn't know what to evaluate (I think). | | Not sure what you mean here. | | > In addition, making pattern matching strict in this way makes it hard to | > mix and match strict and lazy data types (e.g. Maybe), because using a | > lazy data type from another module will make it appear strict in your | > code (hurting modularity). | | I don't think this is a case about modularity. A lazy Maybe value | defined in a lazy module remains lazy; and you can pass it to lazy | functions without forcing it. Only when you pattern match on it *in the | strict module*, the evaluation happens. | | As I said, I prefer this semantics mainly because it's easier to | explain: all variables (and underscores) bound in a strict module refer | to WHNF values. Do you have a similarly simple explanation for the | semantics you're suggesting? | | Roman _______________________________________________ ghc-devs mailing list [hidden email] http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
Reply | Threaded
Open this post in threaded view
|

## RE: -XStrict: Why some binders are not made strict?

 In reply to this post by Johan Tibell-2 In addition, making pattern matching strict in this way makes it hard to mix and match strict and lazy data types (e.g. Maybe), because using a lazy data type from another module will make it appear strict in your code (hurting modularity).   I didn’t understand that.   Simon   From: ghc-devs [mailto:[hidden email]] On Behalf Of Johan Tibell Sent: 11 December 2015 12:22 To: Roman Cheplyaka <[hidden email]> Cc: [hidden email] Subject: Re: -XStrict: Why some binders are not made strict?   I believe Scala has optional lazy values, but you could also consider in strict languages if you do manual thunking.   If we force strictness all the way down it's not really call-by-value either, because the caller doesn't know what to evaluate (I think).   In addition, making pattern matching strict in this way makes it hard to mix and match strict and lazy data types (e.g. Maybe), because using a lazy data type from another module will make it appear strict in your code (hurting modularity).   On Fri, Dec 11, 2015 at 7:54 AM, Roman Cheplyaka <[hidden email]> wrote: On 12/10/2015 04:34 PM, Johan Tibell wrote: > I'm snowed under but I promise I will try to reply soon! To think about > in the mean time: what do existing strict languages with pattern > matching do? Well, strict languages do not have lazy data to force to begin with, do they? Personally, I find the simple intuition of "all patterns are strict by default" rather appealing. E.g. I wouldn't expect the expressions   let (v1,v2) = a in f v2 and   let (v1,v2) = a; v3 = v2 in f v3 to have different semantics. If we decide to adopt this semantics, we need to address the meaning of the pattern   ~(v1, v2) under -XStrict. Intuitively, ~ should propagate to the subpatterns. An alternative is to disallow this pattern under -XStrict and require writing all ~s explicitly, which may get tedious:   ~(~v1, ~v2)   ~(~v1, ~(~v2, ~v3))   etc. We also need to ensure the consistency between this extension and the unlifted data types proposal [1], given their similarity. Interestingly, I don't see constructor patterns explained there either. [1]: https://ghc.haskell.org/trac/ghc/wiki/UnliftedDataTypes#Dynamicsemanticsofunliftedtypes _______________________________________________ ghc-devs mailing list [hidden email] http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs   _______________________________________________ ghc-devs mailing list [hidden email] http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
Reply | Threaded
Open this post in threaded view
|

## Re: -XStrict: Why some binders are not made strict?

 In reply to this post by Simon Peyton Jones Thanks Simon, this is an interesting and compelling interpretation. But I'm wondering whether it is enough to specify the dynamic semantics unambiguously. Two examples: 1.   let _ = undefined in () Intuitively, since we are talking about /strictness/, this should evaluate to bottom. However, it seems that your rule also admits () as an answer; it is equivalent to () under lazy evaluation *and* it does not create any thunks. 2.   f g = g undefined When compiled lazily, this code doesn't construct any thunks:   f = \r srt:SRT:[02v :-> undefined] [g_suM] g_suM undefined; So, under your rule, this is an admissible code for -XStrict, too. But we can hardly call it strict. On 12/12/2015 12:38 AM, Simon Peyton Jones wrote: > | As I said, I prefer this semantics mainly because it's easier to > | explain: all variables (and underscores) bound in a strict module refer > | to WHNF values. Do you have a similarly simple explanation for the > | semantics you're suggesting? > > Here's one, which is roughly what the current implementation does (modulo bugs): > > * Code compiled under -XStrict constructs no thunks. > > So consider > > module M1 where data T = C Int Int > module M2 where f n = C (n+1) (n-1) > module M3 where g x = let C y z = f x in ... > > Look at M3.  Usually we'd get a thunk for (f 4), but not with -XStrict.  But even with -XStrict in M3, y,z might be bound to thunks.   > > If you compile M2 with -XStrict, function f won't build thunks for (n+1), (n-1) but will evaluate them instead. > > If you compile M1 with StrictData, then C is made strict, so again M2 will build no thunks even if M2 was compiled without -XStrict. > > I quite like this design.  It's not clear to me that anything useful is gained by forcing y and z in M3 before evaluating the body "...". > > > So Roman's design makes sense, but so does the implemented design (modulo any bugs).  The trouble is that the implemented design is not well described. > > Simon > > | -----Original Message----- > | From: ghc-devs [mailto:[hidden email]] On Behalf Of Roman > | Cheplyaka > | Sent: 11 December 2015 12:57 > | To: Johan Tibell <[hidden email]> > | Cc: [hidden email] > | Subject: Re: -XStrict: Why some binders are not made strict? > | > | On 12/11/2015 02:21 PM, Johan Tibell wrote: > | > If we force strictness all the way down it's not really call-by-value > | > either, because the caller doesn't know what to evaluate (I think). > | > | Not sure what you mean here. > | > | > In addition, making pattern matching strict in this way makes it hard to > | > mix and match strict and lazy data types (e.g. Maybe), because using a > | > lazy data type from another module will make it appear strict in your > | > code (hurting modularity). > | > | I don't think this is a case about modularity. A lazy Maybe value > | defined in a lazy module remains lazy; and you can pass it to lazy > | functions without forcing it. Only when you pattern match on it *in the > | strict module*, the evaluation happens. > | > | As I said, I prefer this semantics mainly because it's easier to > | explain: all variables (and underscores) bound in a strict module refer > | to WHNF values. Do you have a similarly simple explanation for the > | semantics you're suggesting? > | > | Roman > _______________________________________________ ghc-devs mailing list [hidden email] http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs signature.asc (836 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

## Re: -XStrict: Why some binders are not made strict?

 Hello, Given the upcoming 8.0 feature freeze I think the correct approach for 8.0 is to document the current implementation (I'll try to do that this week). It would probably be good if interested parties would document their input in a ticket. Cheers, --Adam On Sat, 12 Dec 2015, at 12:55 AM, Roman Cheplyaka wrote: > Thanks Simon, this is an interesting and compelling interpretation. But > I'm wondering whether it is enough to specify the dynamic semantics > unambiguously. > > Two examples: > > 1. > >   let _ = undefined in () > > Intuitively, since we are talking about /strictness/, this should > evaluate to bottom. However, it seems that your rule also admits () as > an answer; it is equivalent to () under lazy evaluation *and* it does > not create any thunks. > > 2. > >   f g = g undefined > > When compiled lazily, this code doesn't construct any thunks: > >   f = \r srt:SRT:[02v :-> undefined] [g_suM] g_suM undefined; > > So, under your rule, this is an admissible code for -XStrict, too. But > we can hardly call it strict. > > On 12/12/2015 12:38 AM, Simon Peyton Jones wrote: > > | As I said, I prefer this semantics mainly because it's easier to > > | explain: all variables (and underscores) bound in a strict module refer > > | to WHNF values. Do you have a similarly simple explanation for the > > | semantics you're suggesting? > > > > Here's one, which is roughly what the current implementation does (modulo bugs): > > > > * Code compiled under -XStrict constructs no thunks. > > > > So consider > > > > module M1 where data T = C Int Int > > module M2 where f n = C (n+1) (n-1) > > module M3 where g x = let C y z = f x in ... > > > > Look at M3.  Usually we'd get a thunk for (f 4), but not with -XStrict.  But even with -XStrict in M3, y,z might be bound to thunks.   > > > > If you compile M2 with -XStrict, function f won't build thunks for (n+1), (n-1) but will evaluate them instead. > > > > If you compile M1 with StrictData, then C is made strict, so again M2 will build no thunks even if M2 was compiled without -XStrict. > > > > I quite like this design.  It's not clear to me that anything useful is gained by forcing y and z in M3 before evaluating the body "...". > > > > > > So Roman's design makes sense, but so does the implemented design (modulo any bugs).  The trouble is that the implemented design is not well described. > > > > Simon > > > > | -----Original Message----- > > | From: ghc-devs [mailto:[hidden email]] On Behalf Of Roman > > | Cheplyaka > > | Sent: 11 December 2015 12:57 > > | To: Johan Tibell <[hidden email]> > > | Cc: [hidden email] > > | Subject: Re: -XStrict: Why some binders are not made strict? > > | > > | On 12/11/2015 02:21 PM, Johan Tibell wrote: > > | > If we force strictness all the way down it's not really call-by-value > > | > either, because the caller doesn't know what to evaluate (I think). > > | > > | Not sure what you mean here. > > | > > | > In addition, making pattern matching strict in this way makes it hard to > > | > mix and match strict and lazy data types (e.g. Maybe), because using a > > | > lazy data type from another module will make it appear strict in your > > | > code (hurting modularity). > > | > > | I don't think this is a case about modularity. A lazy Maybe value > > | defined in a lazy module remains lazy; and you can pass it to lazy > > | functions without forcing it. Only when you pattern match on it *in the > > | strict module*, the evaluation happens. > > | > > | As I said, I prefer this semantics mainly because it's easier to > > | explain: all variables (and underscores) bound in a strict module refer > > | to WHNF values. Do you have a similarly simple explanation for the > > | semantics you're suggesting? > > | > > | Roman > > > > > _______________________________________________ > ghc-devs mailing list > [hidden email] > http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs> Email had 1 attachment: > + signature.asc >   1k (application/pgp-signature) _______________________________________________ ghc-devs mailing list [hidden email] http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
Reply | Threaded
Open this post in threaded view
|

## Re: -XStrict: Why some binders are not made strict?

 Agreed.(Sorry for the sporadic communication. This is a very busy time at work.)I thought about this a bit more recently.Here's one way where I think "force every binder" goes wrong:-- In a Strict modulef (Just x) = Just xThis is not the identity. This might matter in practice if a user defines a data type, in a lazy module, that uses a lazy field to cache an expensive calculation:-- In a lazy module:data CachedHash = CH a IntmkCH x = CH x (expensiveHash x)The intention here is that we only evaluate the expensive hash function when needed. However, if we evaluate every binder this is no longer transparent to users of the module, because doing this forces both fields:f (CH x h) = CH x hThis also seems a bit "one sided" in that we do not evaluate expr in `Just ` under Strict, to not break modularity, but we would do it if you pattern-matched on the contents of Just.I'm also worried that we might make a choice here that we can't undo. I at least understand the meaning of Strict in relation to strict languages. "Evaluate every binder" is a new thing. Perhaps it deserves its own pragma, StrictBinders.On Mon, Dec 14, 2015 at 6:50 PM, Adam Sandberg Eriksson wrote:Hello, Given the upcoming 8.0 feature freeze I think the correct approach for 8.0 is to document the current implementation (I'll try to do that this week). It would probably be good if interested parties would document their input in a ticket. Cheers, --Adam On Sat, 12 Dec 2015, at 12:55 AM, Roman Cheplyaka wrote: > Thanks Simon, this is an interesting and compelling interpretation. But > I'm wondering whether it is enough to specify the dynamic semantics > unambiguously. > > Two examples: > > 1. > >   let _ = undefined in () > > Intuitively, since we are talking about /strictness/, this should > evaluate to bottom. However, it seems that your rule also admits () as > an answer; it is equivalent to () under lazy evaluation *and* it does > not create any thunks. > > 2. > >   f g = g undefined > > When compiled lazily, this code doesn't construct any thunks: > >   f = \r srt:SRT:[02v :-> undefined] [g_suM] g_suM undefined; > > So, under your rule, this is an admissible code for -XStrict, too. But > we can hardly call it strict. > > On 12/12/2015 12:38 AM, Simon Peyton Jones wrote: > > | As I said, I prefer this semantics mainly because it's easier to > > | explain: all variables (and underscores) bound in a strict module refer > > | to WHNF values. Do you have a similarly simple explanation for the > > | semantics you're suggesting? > > > > Here's one, which is roughly what the current implementation does (modulo bugs): > > > > * Code compiled under -XStrict constructs no thunks. > > > > So consider > > > >     module M1 where data T = C Int Int > >     module M2 where f n = C (n+1) (n-1) > >     module M3 where g x = let C y z = f x in ... > > > > Look at M3.  Usually we'd get a thunk for (f 4), but not with -XStrict.  But even with -XStrict in M3, y,z might be bound to thunks. > > > > If you compile M2 with -XStrict, function f won't build thunks for (n+1), (n-1) but will evaluate them instead. > > > > If you compile M1 with StrictData, then C is made strict, so again M2 will build no thunks even if M2 was compiled without -XStrict. > > > > I quite like this design.  It's not clear to me that anything useful is gained by forcing y and z in M3 before evaluating the body "...". > > > > > > So Roman's design makes sense, but so does the implemented design (modulo any bugs).  The trouble is that the implemented design is not well described. > > > > Simon > > > > | -----Original Message----- > > | From: ghc-devs [mailto:[hidden email]] On Behalf Of Roman > > | Cheplyaka > > | Sent: 11 December 2015 12:57 > > | To: Johan Tibell <[hidden email]> > > | Cc: [hidden email] > > | Subject: Re: -XStrict: Why some binders are not made strict? > > | > > | On 12/11/2015 02:21 PM, Johan Tibell wrote: > > | > If we force strictness all the way down it's not really call-by-value > > | > either, because the caller doesn't know what to evaluate (I think). > > | > > | Not sure what you mean here. > > | > > | > In addition, making pattern matching strict in this way makes it hard to > > | > mix and match strict and lazy data types (e.g. Maybe), because using a > > | > lazy data type from another module will make it appear strict in your > > | > code (hurting modularity). > > | > > | I don't think this is a case about modularity. A lazy Maybe value > > | defined in a lazy module remains lazy; and you can pass it to lazy > > | functions without forcing it. Only when you pattern match on it *in the > > | strict module*, the evaluation happens. > > | > > | As I said, I prefer this semantics mainly because it's easier to > > | explain: all variables (and underscores) bound in a strict module refer > > | to WHNF values. Do you have a similarly simple explanation for the > > | semantics you're suggesting? > > | > > | Roman > > > > > _______________________________________________ > ghc-devs mailing list > [hidden email] > http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs > Email had 1 attachment: > + signature.asc >   1k (application/pgp-signature) _______________________________________________ ghc-devs mailing list [hidden email] http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
Reply | Threaded
Open this post in threaded view
|

## RE: -XStrict: Why some binders are not made strict?

 In reply to this post by Adam Sandberg Eriksson | Given the upcoming 8.0 feature freeze I think the correct approach for | 8.0 is to document the current implementation (I'll try to do that this | week). Yes, that's right.  Thanks! Simon | | It would probably be good if interested parties would document their | input in a ticket. | | Cheers, | --Adam | | | On Sat, 12 Dec 2015, at 12:55 AM, Roman Cheplyaka wrote: | > Thanks Simon, this is an interesting and compelling interpretation. But | > I'm wondering whether it is enough to specify the dynamic semantics | > unambiguously. | > | > Two examples: | > | > 1. | > | >   let _ = undefined in () | > | > Intuitively, since we are talking about /strictness/, this should | > evaluate to bottom. However, it seems that your rule also admits () as | > an answer; it is equivalent to () under lazy evaluation *and* it does | > not create any thunks. | > | > 2. | > | >   f g = g undefined | > | > When compiled lazily, this code doesn't construct any thunks: | > | >   f = \r srt:SRT:[02v :-> undefined] [g_suM] g_suM undefined; | > | > So, under your rule, this is an admissible code for -XStrict, too. But | > we can hardly call it strict. | > | > On 12/12/2015 12:38 AM, Simon Peyton Jones wrote: | > > | As I said, I prefer this semantics mainly because it's easier to | > > | explain: all variables (and underscores) bound in a strict module refer | > > | to WHNF values. Do you have a similarly simple explanation for the | > > | semantics you're suggesting? | > > | > > Here's one, which is roughly what the current implementation does (modulo | bugs): | > > | > > * Code compiled under -XStrict constructs no thunks. | > > | > > So consider | > > | > > module M1 where data T = C Int Int | > > module M2 where f n = C (n+1) (n-1) | > > module M3 where g x = let C y z = f x in ... | > > | > > Look at M3.  Usually we'd get a thunk for (f 4), but not with -XStrict. | But even with -XStrict in M3, y,z might be bound to thunks. | > > | > > If you compile M2 with -XStrict, function f won't build thunks for (n+1), | (n-1) but will evaluate them instead. | > > | > > If you compile M1 with StrictData, then C is made strict, so again M2 | will build no thunks even if M2 was compiled without -XStrict. | > > | > > I quite like this design.  It's not clear to me that anything useful is | gained by forcing y and z in M3 before evaluating the body "...". | > > | > > | > > So Roman's design makes sense, but so does the implemented design (modulo | any bugs).  The trouble is that the implemented design is not well described. | > > | > > Simon | > > | > > | -----Original Message----- | > > | From: ghc-devs [mailto:[hidden email]] On Behalf Of Roman | > > | Cheplyaka | > > | Sent: 11 December 2015 12:57 | > > | To: Johan Tibell <[hidden email]> | > > | Cc: [hidden email] | > > | Subject: Re: -XStrict: Why some binders are not made strict? | > > | | > > | On 12/11/2015 02:21 PM, Johan Tibell wrote: | > > | > If we force strictness all the way down it's not really call-by-value | > > | > either, because the caller doesn't know what to evaluate (I think). | > > | | > > | Not sure what you mean here. | > > | | > > | > In addition, making pattern matching strict in this way makes it hard | to | > > | > mix and match strict and lazy data types (e.g. Maybe), because using | a | > > | > lazy data type from another module will make it appear strict in your | > > | > code (hurting modularity). | > > | | > > | I don't think this is a case about modularity. A lazy Maybe value | > > | defined in a lazy module remains lazy; and you can pass it to lazy | > > | functions without forcing it. Only when you pattern match on it *in the | > > | strict module*, the evaluation happens. | > > | | > > | As I said, I prefer this semantics mainly because it's easier to | > > | explain: all variables (and underscores) bound in a strict module refer | > > | to WHNF values. Do you have a similarly simple explanation for the | > > | semantics you're suggesting? | > > | | > > | Roman | > > | > | > | > _______________________________________________ | > ghc-devs mailing list | > [hidden email] | > | https://na01.safelinks.protection.outlook.com/?url=http%3a%2f%2fmail.haskell. | org%2fcgi-bin%2fmailman%2flistinfo%2fghc- | devs&data=01%7c01%7csimonpj%40064d.mgd.microsoft.com%7c81ebe250762640019a7b08 | d304af0dcc%7c72f988bf86f141af91ab2d7cd011db47%7c1&sdata=qy2g8Dy4zDVKohNOHLnYT | ekaVLtckBwTtOvN6y4cUuo%3d | > Email had 1 attachment: | > + signature.asc | >   1k (application/pgp-signature) _______________________________________________ ghc-devs mailing list [hidden email] http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
Reply | Threaded
Open this post in threaded view
|

## RE: -XStrict: Why some binders are not made strict?

 In reply to this post by Roman Cheplyaka-2 |  Thanks Simon, this is an interesting and compelling interpretation. |  But I'm wondering whether it is enough to specify the dynamic |  semantics unambiguously. You make good points.  Also, consider         f (g x) where f is define in some other (lazy) module.  Is that done call-by value?  That is, is (g x) evaluated before the call?  According to the current spec, no. So a thunk is built! But if we write         let y = g x in f y then, lo, the (g x) is computed eagerly. So the present semantics seems to be more         functions always evaluate their arguments to       WHNF (but not to NF)! I do think this could do with a tighter spec.  Johan, Adam, this is your baby. Simon |  -----Original Message----- |  From: Roman Cheplyaka [mailto:[hidden email]] |  Sent: 11 December 2015 23:56 |  To: Simon Peyton Jones <[hidden email]>; Johan Tibell |  <[hidden email]> |  Cc: [hidden email] |  Subject: Re: -XStrict: Why some binders are not made strict? |   |  Thanks Simon, this is an interesting and compelling interpretation. |  But I'm wondering whether it is enough to specify the dynamic |  semantics unambiguously. |   |  Two examples: |   |  1. |   |    let _ = undefined in () |   |  Intuitively, since we are talking about /strictness/, this should |  evaluate to bottom. However, it seems that your rule also admits () as |  an answer; it is equivalent to () under lazy evaluation *and* it does |  not create any thunks. |   |  2. |   |    f g = g undefined |   |  When compiled lazily, this code doesn't construct any thunks: |   |    f = \r srt:SRT:[02v :-> undefined] [g_suM] g_suM undefined; |   |  So, under your rule, this is an admissible code for -XStrict, too. But |  we can hardly call it strict. |   |  On 12/12/2015 12:38 AM, Simon Peyton Jones wrote: |  > | As I said, I prefer this semantics mainly because it's easier to |  > | explain: all variables (and underscores) bound in a strict module |  > | refer to WHNF values. Do you have a similarly simple explanation |  for |  > | the semantics you're suggesting? |  > |  > Here's one, which is roughly what the current implementation does |  (modulo bugs): |  > |  > * Code compiled under -XStrict constructs no thunks. |  > |  > So consider |  > |  > module M1 where data T = C Int Int |  > module M2 where f n = C (n+1) (n-1) |  > module M3 where g x = let C y z = f x in ... |  > |  > Look at M3.  Usually we'd get a thunk for (f 4), but not with - |  XStrict.  But even with -XStrict in M3, y,z might be bound to thunks. |  > |  > If you compile M2 with -XStrict, function f won't build thunks for |  (n+1), (n-1) but will evaluate them instead. |  > |  > If you compile M1 with StrictData, then C is made strict, so again |  M2 will build no thunks even if M2 was compiled without -XStrict. |  > |  > I quite like this design.  It's not clear to me that anything useful |  is gained by forcing y and z in M3 before evaluating the body "...". |  > |  > |  > So Roman's design makes sense, but so does the implemented design |  (modulo any bugs).  The trouble is that the implemented design is not |  well described. |  > |  > Simon |  > |  > | -----Original Message----- |  > | From: ghc-devs [mailto:[hidden email]] On Behalf Of |  > | Roman Cheplyaka |  > | Sent: 11 December 2015 12:57 |  > | To: Johan Tibell <[hidden email]> |  > | Cc: [hidden email] |  > | Subject: Re: -XStrict: Why some binders are not made strict? |  > | |  > | On 12/11/2015 02:21 PM, Johan Tibell wrote: |  > | > If we force strictness all the way down it's not really |  > | > call-by-value either, because the caller doesn't know what to |  evaluate (I think). |  > | |  > | Not sure what you mean here. |  > | |  > | > In addition, making pattern matching strict in this way makes it |  > | > hard to mix and match strict and lazy data types (e.g. Maybe), |  > | > because using a lazy data type from another module will make it |  > | > appear strict in your code (hurting modularity). |  > | |  > | I don't think this is a case about modularity. A lazy Maybe value |  > | defined in a lazy module remains lazy; and you can pass it to lazy |  > | functions without forcing it. Only when you pattern match on it |  *in |  > | the strict module*, the evaluation happens. |  > | |  > | As I said, I prefer this semantics mainly because it's easier to |  > | explain: all variables (and underscores) bound in a strict module |  > | refer to WHNF values. Do you have a similarly simple explanation |  for |  > | the semantics you're suggesting? |  > | |  > | Roman |  > |   _______________________________________________ ghc-devs mailing list [hidden email] http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs