-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathargument-do.trac
167 lines (120 loc) · 6.35 KB
/
argument-do.trac
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
= Overview =
This page documents a proposed syntactical extension called `ArgumentDo`. The feature request is tracked at #10843.
This extension would allow a `do` block, a lambda, and a few other syntactic constructs to be placed directly as a function argument, without parentheses or a `$`. For example,
{{{#!hs
atomically do
v <- readTVar tv
writeTVar tv $! v + 1
}}}
would be equivalent to
{{{#!hs
atomically (do
v <- readTVar tv
writeTVar tv $! v + 1)
}}}
and
{{{#!hs
withForeignPtr fptr \ptr -> c_memcpy buf ptr size
}}}
would be equivalent to
{{{#!hs
withForeignPtr fptr (\ptr -> c_memcpy buf ptr size)
}}}
= Changes to the grammar =
The Haskell report [https://www.haskell.org/onlinereport/haskell2010/haskellch3.html#x8-220003 defines] the `lexp` nonterminal thus (`*` indicates a rule of interest):
{{{
lexp → \ apat1 … apatn -> exp (lambda abstraction, n ≥ 1) *
| let decls in exp (let expression) *
| if exp [;] then exp [;] else exp (conditional) *
| case exp of { alts } (case expression) *
| do { stmts } (do expression) *
| fexp
fexp → [fexp] aexp (function application)
aexp → qvar (variable)
| gcon (general constructor)
| literal
| ( exp ) (parenthesized expression)
| qcon { fbind1 … fbindn } (labeled construction)
| aexp { fbind1 … fbindn } (labelled update)
| …
}}}
which means lambda, `let`, `if`, `case`, and `do` constructs cannot be used as either LHS or RHS of a function application. GHC Haskell has a few more constructs that fall into this category, such as `mdo`, `\case` and `proc` blocks.
The `ArgumentDo` extension would allow all these constructs in argument positions. This is accomplished by moving their production rules under `aexp`:
{{{
lexp → fexp
fexp → [fexp] aexp (function application)
aexp → qvar (variable)
| gcon (general constructor)
| literal
| ( exp ) (parenthesized expression)
| qcon { fbind1 … fbindn } (labeled construction)
| aexp { fbind1 … fbindn } (labelled update)
-- Here are the moved rules
| \ apat1 … apatn -> exp (lambda abstraction, n ≥ 1) *
| let decls in exp (let expression) *
| if exp [;] then exp [;] else exp (conditional) *
| case exp of { alts } (case expression) *
| do { stmts } (do expression) *
| …
}}}
Now the `lexp` nonterminal is redundant and can be dropped from the grammar.
Note that this change relies on an existing meta-rule to resolve ambiguities:
> The grammar is ambiguous regarding the extent of lambda abstractions, let expressions, and conditionals. The ambiguity is resolved by the meta-rule that each of these constructs extends as far to the right as possible.
For example, `f \a -> a b` will be parsed as `f (\a -> a b)`, not as `f (\a -> a) b`.
= Less obvious examples =
== Deleting parentheses ==
This extension will most often allow deletion of just one `$` operator per application. However, sometimes it does more. For example, in the following example, you can't simply replace the parentheses with a `$`:
{{{#!hs
pi + f (do
...
)
}}}
With `ArgumentDo`, you would be able to write the following instead:
{{{#!hs
pi + f do
...
}}}
== Multiple block arguments ==
A function may take multiple `do` blocks:
{{{#!hs
f do{ x } do { y }
}}}
or
{{{#!hs
f
do x
do y
}}}
== Block as a LHS
A `do` block can be LHS of a function application:
{{{#!hs
do f &&& g
x
}}}
would just mean
{{{#!hs
(f &&& g) x
}}}
= Design space =
Possible modifications to the proposal include:
* Only allow `do` in argument positions, but no other constructs. This has an advantage of making a minimal change to the grammar, while addressing the most common case.
This proposal has been extensively discussed on [https://mail.haskell.org/pipermail/haskell-cafe/2015-September/121217.html haskell-cafe] and on [https://www.reddit.com/r/haskell/comments/447bnw/does_argument_do_have_a_future/ reddit].
On the mailing list I see roughly 13 people in favor of the proposal and 12 people against it. Some major opinions (mostly copied from [https://ghc.haskell.org/trac/ghc/ticket/10843#comment:12 bgmari's summary]).
== Pros ==
* It's easier to read than the alternative.
* This extension removes syntactic noise.
* This makes basic do-syntax more approachable to newbies; it is a commonly asked question as to why the $ is necessary.
* This simplifies the resulting AST, potentially making it simpler for editors and other tools to do refactoring.
* It's something that belongs in the main language, and if its something we'd consider for a mythical Haskell', it has to start as an extension.
* It gets rid of some cases where using $ doesn't work because $ interacts with other infix operators being used in the same expression.
* This would make do blocks consistent with record creation, where parentheses are skipped, allowing things such as return R { x = y}
* This does not change the meaning of any old programs, only allows new ones that were previously forbidden.
* This gets rid of the need for a specially-typed $ allowing runSt $ do ...
* It allows unparenthesized non-trivial application arguments not only as the last argument (using `$`), but for all arguments, in separate lines, when headed by `do` or another group A construct.
* It makes the language more regular by reducing the number of nonterminals by one.
== Cons ==
* It's harder to read than the alternative.
* Creating a language extension to get rid of a single character is overkill and unnecessary.
* You can already get rid of the $ by just adding parentheses.
* More and more syntactic "improvements" just fragment the language.
* Although this is consistent with record syntax, record syntax without parents was a mistake originally.