[Haskell-cafe] Surprising interaction between @-patterns and nested patterns

David Feuer david.feuer at gmail.com
Tue Jan 3 02:09:28 UTC 2023


My opinion, for several years, has been that the Haskell designers erred in
making outermost patterns lazy by default in let and where, and at the top
level. I believe they should have gone with something much simpler:

1. Patterns are strict by default.
2. Variables are lazy by default.
3. Patterns at the top level must be marked lazy.
4. (With bang patterns) Variables at the top level may not be marked strict.

That would harmonize the way patterns are handled in let and where with the
way they're handled in function arguments and case expressions, as well as
removing the outermost-pattern special case which makes the *strictness* of
inner patterns surprising. Unfortunately, I don't think there's much chance
of any of these changing in Haskell.

On Mon, Jan 2, 2023, 6:00 PM Tom Ellis <
tom-lists-haskell-cafe-2017 at jaguarpaw.co.uk> wrote:

> Consider the following:
>
>     let x0 = (undefined, ()) ; ((_, _), _) = x0 in x0 `seq` ()
>     ()
>
> but then combining the patterns into an @-pattern, which really feels
> like it shouldn't change semantics:
>
>     let x1@((_, _), _) = (undefined, ()) in x1 `seq` ()
>     -> undefined
>
> Does this strike anyone else as odd?  The reason for this behaviour is
> that
>
>     let x at p = rhs in body
>
> is translated to
>
>     case rhs of ~(x at p) -> body
>
> according to section 3.12 of The Report[1] which is then translated to
>
>     (\x -> body) (case rhs of x at p -> x)
>
> if p binds no variables, according to section 3.17.3 of The Report[2],
> and then to
>
>     (\x -> body) (case rhs of p -> (\x -> x) rhs)
>
> which is equivalent to
>
>     (\x -> body) (case rhs of p -> rhs)
>
> Putting it all together
>
>     let x0 = (undefined, ()) ; ((_, _), _) = x0 in x0 `seq` ()
>
> desugars as
>
>     (\x0 -> x0 `seq` ())
>     (let v = (undefined, ()) in case v of ((_, _), _) -> v)
>
> which evaluates as
>
>     let v = (undefined, ())
>     in case v of ((_, _), _) -> ()
>
>
> This seems very odd to me.  Why should combining two non-diverging
> patterns into an @-pattern cause divergence?  Specifically, the
> translation from
>
>     let x at p = rhs in body
>
> to
>
>     case rhs of ~(x at p) -> body
>
> seems highly dubious.  It comes from the more general rule translating
>
>     let p = rhs in body
>
> to
>
>     case rhs of ~p in body
>
> but it seems to interact badly with @-patterns.  It seems like the
> rule for @-patterns should be something like
>
>     let x at p = rhs in body
>
> translates to
>
>     case rhs of ~(x@(~p)) in body
>
> Then the original expression containing x1 would not diverge.
>
> Does anyone else have a view on this matter?
>
> Tom
>
>
> [1] https://www.haskell.org/onlinereport/exps.html#sect3.12
>
> [2] https://www.haskell.org/onlinereport/exps.html#sect3.17.3
> _______________________________________________
> Haskell-Cafe mailing list
> To (un)subscribe, modify options or view archives go to:
> http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
> Only members subscribed via the mailman list are allowed to post.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/haskell-cafe/attachments/20230102/6b056ce4/attachment.html>


More information about the Haskell-Cafe mailing list