| 124 | == Top-level bang-pattern bindings == |
| 125 | |
| 126 | Does this make sense? |
| 127 | {{{ |
| 128 | module Foo where |
| 129 | !x = factorial 1000 |
| 130 | }}} |
| 131 | A top-level bang-pattern binding like this would imply that |
| 132 | the binding is evaluated when the program is started; a kind of |
| 133 | module initialisation. This makes some kind of sense, since |
| 134 | (unlike unrestricted side effects) it doesn't matter in which order |
| 135 | the module initialisation is performed. |
| 136 | |
| 137 | But it's not clear why it would be necessary or useful. Conservative |
| 138 | conclusion: no top-level bang-patterns. |
| 139 | |
| 140 | == Recursive let and where bindings == |
| 141 | |
| 142 | It is just about possible to make sense of bang-patterns in |
| 143 | ''recursive'' let and where bindings. At first you might think they |
| 144 | don't make sense: how can you evaluate it strictly if it doesn't exist |
| 145 | yet? But consider |
| 146 | {{{ |
| 147 | let !xs = if funny then 1:xs else 2:xs in ... |
| 148 | }}} |
| 149 | Here the binding is recursive, but makes sense to think of it |
| 150 | as equivalent to |
| 151 | {{{ |
| 152 | let xs = if funny then 1:xs else 2:xs |
| 153 | in xs `seq` ... |
| 154 | }}} |
| 155 | But (a) it must be unusual, and (b) I have found it very hard to |
| 156 | come up with a plausible translation (that deals with all the tricky |
| 157 | points). |
| 158 | |
| 159 | Conservative conclusion: bang-pattern bindings must be non-recursive. |
| 160 | |
| 161 | === Tricky point: syntax === |
| 162 | |
| 163 | What does this mean? |
| 164 | {{{ |
| 165 | f ! x = True |
| 166 | }}} |
| 167 | Is this a definition of `(!)` or a banged argument? (Assuming that |
| 168 | space is insignificant.) |
| 169 | |
| 170 | Proposal: resolve this ambiguity in favour of the bang-pattern. If |
| 171 | you want to define `(!)`, use the prefix form |
| 172 | {{{ |
| 173 | (!) f x = True |
| 174 | }}} |
| 175 | |
| 176 | === Tricky point: nested bangs === |
| 177 | |
| 178 | Consider this: |
| 179 | {{{ |
| 180 | let !(x, Just !y) = <rhs> in <body> |
| 181 | }}} |
| 182 | This should be equivalent to |
| 183 | {{{ |
| 184 | case <rhs> of { (x, Just !y) -> <body> } |
| 185 | }}} |
| 186 | Notice that this meant that the '''entire''' pattern is matched |
| 187 | (as always with Haskell). The `Just` may fail; `x` is |
| 188 | not evaluated; but `y` '''is''' evaluated. |
| 189 | |
| 190 | == Tricky point: polymorphism == |
| 191 | |
| 192 | Haskell allows this: |
| 193 | {{{ |
| 194 | let f :: forall a. Num a => a->a |
| 195 | Just f = <rhs> |
| 196 | in (f (1::Int), f (2::Integer)) |
| 197 | }}} |
| 198 | But if we were to allow a bang pattern, `!Just f = <rhs>`, |
| 199 | with the translation to |
| 200 | a case expression given earlier, we would end up with |
| 201 | {{{ |
| 202 | case <rhs> of { Just f -> (f (1::Int), f (2::Integer) } |
| 203 | }}} |
| 204 | But if this is Haskell source, then `f` won't be polymorphic. |
| 205 | |
| 206 | |