|
|
|
# Proposal: [StricterLabelledFieldSyntax](stricter-labelled-field-syntax)
|
|
|
|
|
|
|
|
|
|
|
|
<table><tr><th> Ticket </th>
|
|
|
|
<th>[\#132](https://gitlab.haskell.org//haskell/prime/issues/132)</th></tr>
|
|
|
|
<th> [\#132](https://gitlab.haskell.org//haskell/prime/issues/132)
|
|
|
|
</th></tr>
|
|
|
|
<tr><th> Dependencies </th>
|
|
|
|
<th> none
|
|
|
|
</th></tr>
|
| ... | ... | @@ -9,8 +11,10 @@ |
|
|
|
<th> none
|
|
|
|
</th></tr></table>
|
|
|
|
|
|
|
|
|
|
|
|
## Compiler support
|
|
|
|
|
|
|
|
|
|
|
|
<table><tr><th> GHC </th>
|
|
|
|
<th> partial (test patch available)
|
|
|
|
</th></tr>
|
| ... | ... | @@ -30,36 +34,21 @@ |
|
|
|
<th> none
|
|
|
|
</th></tr></table>
|
|
|
|
|
|
|
|
## Summary
|
|
|
|
|
|
|
|
|
|
|
|
Make the labelled field syntax stricter, so that unclear code is illegal.
|
|
|
|
|
|
|
|
|
|
|
|
Instead of:
|
|
|
|
|
|
|
|
```wiki
|
|
|
|
data A = A {x :: Int}
|
|
|
|
|
|
|
|
y :: Maybe A
|
|
|
|
y = Just A {x = 5}
|
|
|
|
```
|
|
|
|
## Summary
|
|
|
|
|
|
|
|
|
|
|
|
you would need to write:
|
|
|
|
|
|
|
|
```wiki
|
|
|
|
data A = A {x :: Int}
|
|
|
|
Make the labelled field syntax stricter, so that unclear code is illegal.
|
|
|
|
|
|
|
|
y :: Maybe A
|
|
|
|
y = Just (A {x = 5})
|
|
|
|
```
|
|
|
|
|
|
|
|
## Description
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Many people believe that the precedence of labelled fields creation, updates and pattern matching can lead to confusing code. For example, in [ http://hackage.haskell.org/trac/ghc/ticket/2530](http://hackage.haskell.org/trac/ghc/ticket/2530) it was reported that this program:
|
|
|
|
|
|
|
|
|
|
|
|
```wiki
|
|
|
|
module Main where
|
|
|
|
|
| ... | ... | @@ -72,6 +61,7 @@ main = print $ Just A {x = 5} |
|
|
|
|
|
|
|
(correctly, according to Haskell 98) prints
|
|
|
|
|
|
|
|
|
|
|
|
```wiki
|
|
|
|
Just A {x = 5}
|
|
|
|
```
|
| ... | ... | @@ -79,6 +69,7 @@ Just A {x = 5} |
|
|
|
|
|
|
|
in hugs, but the more easily comprehendible
|
|
|
|
|
|
|
|
|
|
|
|
```wiki
|
|
|
|
Just (A {x = 5})
|
|
|
|
```
|
| ... | ... | @@ -87,8 +78,10 @@ Just (A {x = 5}) |
|
|
|
in ghci.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
According to Haskell 98,
|
|
|
|
|
|
|
|
|
|
|
|
```wiki
|
|
|
|
A {x = 5}
|
|
|
|
```
|
| ... | ... | @@ -97,8 +90,10 @@ A {x = 5} |
|
|
|
is an atomic expression - but it doesn't look atomic! This violates the principle of least surprise.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Before coming across labelled fields, but having had "function application binds tightest" drummed into you to understand how to read expressions containing a mixture of applications and infix operators, of the following 2 functions:
|
|
|
|
|
|
|
|
|
|
|
|
```wiki
|
|
|
|
data A = A {x :: Bool} deriving (Show)
|
|
|
|
|
| ... | ... | @@ -110,8 +105,10 @@ g = print $ A True {x = False} |
|
|
|
I would expect `g` to be the correct one, while it is `f` that is correct according to Haskell 98.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
However, once you remove the space before the curly brace:
|
|
|
|
|
|
|
|
|
|
|
|
```wiki
|
|
|
|
h = print $ Just A{x = True}
|
|
|
|
i = print $ A True{x = False}
|
| ... | ... | @@ -120,20 +117,19 @@ i = print $ A True{x = False} |
|
|
|
|
|
|
|
it is `h` that looks more correct. Note that we have a similar problem with infix operators, and expressions like
|
|
|
|
|
|
|
|
|
|
|
|
```wiki
|
|
|
|
1+f x+2
|
|
|
|
```
|
|
|
|
|
|
|
|
**I propose that all of `f`, `g`, `h` and `i` be made illegal, with parentheses being required to disambiguate these cases.**
|
|
|
|
|
|
|
|
|
|
|
|
No additional programs are accepted by this change, and no programs have their behaviour changed. This change only rejects some programs that were previously accepted.
|
|
|
|
I propose that all of `f`, `g`, `h` and `i` be made illegal, with parentheses being required to disambiguate these cases.
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
Here are some real-life examples of what I consider confusing code, from `haskeline`:
|
|
|
|
|
|
|
|
|
|
|
|
```wiki
|
|
|
|
metaKey :: Key -> Key
|
|
|
|
metaKey (Key m bc) = Key m {hasMeta = True} bc
|
| ... | ... | @@ -147,6 +143,7 @@ searchText SearchEntry {entryState = IMode xs ys} = reverse xs ++ ys |
|
|
|
|
|
|
|
and from `Cabal`:
|
|
|
|
|
|
|
|
|
|
|
|
```wiki
|
|
|
|
configure ... = do
|
|
|
|
...
|
| ... | ... | @@ -177,31 +174,21 @@ register pkg@PackageDescription { library = Just lib } |
|
|
|
= ...
|
|
|
|
```
|
|
|
|
|
|
|
|
## Result
|
|
|
|
|
|
|
|
|
|
|
|
There was not a consensus to make this change.
|
|
|
|
|
|
|
|
## References
|
|
|
|
|
|
|
|
|
|
|
|
A patch to add support for the syntax to GHC, as well as patches needed to fix GHC and the libraries to follow the new syntax, are in the ticket ([\#132](https://gitlab.haskell.org//haskell/prime/issues/132)).
|
|
|
|
|
|
|
|
|
|
|
|
This darcs patch is an example of real-world confusion caused by the current parsing:
|
|
|
|
A patch to add support for the syntax to GHC, as well as patches needed to fix GHC and the libraries to follow the new syntax, are in the ticket ([\#132](https://gitlab.haskell.org//haskell/prime/issues/132)).
|
|
|
|
|
|
|
|
```wiki
|
|
|
|
Sun Feb 21 12:59:33 GMT 2010 Eric Kow <kowey@darcs.net>
|
|
|
|
* Resolve issue1750: uncover help text for darcs show pristine.
|
|
|
|
f r { foo = bar } means f (r { foo = bar })
|
|
|
|
whereas what we really wanted was (f r) { foo = bar }
|
|
|
|
```
|
|
|
|
|
|
|
|
## Report Delta
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
In [ Section 3](http://haskell.org/onlinereport/exps.html#sect3) replace:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
exp10 -> ...
|
| ... | ... | @@ -209,8 +196,12 @@ exp10 -> ... |
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
with:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
exp10 -> ...
|
| ... | ... | @@ -221,8 +212,12 @@ recexp -> qcon { fbind1 , ... , fbindn } (labeled construction, n >= 0) |
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
and remove:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
aexp -> ...
|
| ... | ... | @@ -231,48 +226,72 @@ aexp -> ... |
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
In [ Section 3.15.2](http://haskell.org/onlinereport/exps.html#sect3.15.2) replace:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
aexp -> qcon { fbind1 , ... , fbindn } (labeled construction, n>=0)
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
with:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
recexp -> qcon { fbind1 , ... , fbindn } (labeled construction, n >= 0)
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
In [ Section 3.15.3](http://haskell.org/onlinereport/exps.html#sect3.15.3) replace:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
aexp -> aexp<qcon> { fbind1 , ... , fbindn } (labeled update, n >= 1)
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
with:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
recexp -> aexp<qcon> { fbind1 , ... , fbindn } (labeled update, n >= 1)
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
In [ Section 3.17.1](http://haskell.org/onlinereport/exps.html#sect3.17.1) replace:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
pat10 -> ...
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
with:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
pat10 -> ...
|
| ... | ... | @@ -280,8 +299,12 @@ pat10 -> ... |
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
and remove:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
apat -> ...
|
| ... | ... | @@ -289,8 +312,12 @@ apat -> ... |
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
In [ Section 9.5](http://haskell.org/onlinereport/syntax-iso.html#sect9.5) replace:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
exp10 -> ...
|
| ... | ... | @@ -298,8 +325,12 @@ exp10 -> ... |
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
with:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
exp10 -> ...
|
| ... | ... | @@ -310,8 +341,12 @@ recexp -> qcon { fbind1 , ... , fbindn } (labeled construction, n >= 0) |
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
and remove:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
aexp -> ...
|
| ... | ... | @@ -320,16 +355,24 @@ aexp -> ... |
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
and replace
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
pat10 -> ...
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
with:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
pat10 -> ...
|
| ... | ... | @@ -337,10 +380,17 @@ pat10 -> ... |
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
and remove:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
apat -> ...
|
|
|
|
| qcon { fpat1 , ... , fpatk } (labeled pattern, k>=0)
|
|
|
|
``` |
|
|
\ No newline at end of file |
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|