165 | | * Introduce a new primop `seq# :: a -> State# s -> (# a, State# s #)` |
166 | | * An application of the primop is not considered cheap. |
167 | | * Desugar `seq` thus: |
| 165 | * Introduce a new primop `seq# :: a -> State# s -> (# a, State# s #)` (see be5441799b7d94646dcd4bfea15407883537eaaa) |
| 166 | * Implement `seq#` by turning it into the obvious eval in the backend. In fact, since the return convention for `(# State# s, a #)` is exactly the same as for `a`, we can implement `seq# s a` by `a` (even when it appears as a case scrutinee). Currenntly |
| 167 | * Define `evaluate` thus |
| 168 | {{{ |
| 169 | evaluate :: a -> IO a |
| 170 | evaluate x = IO $ \s -> seq# x s |
| 171 | }}} |
| 172 | |
| 173 | That fixes problem 4. |
| 174 | |
| 175 | We could go on and desugar `seq` thus: |
172 | | * Define `evaluate` thus |
173 | | {{{ |
174 | | evaluate :: a -> IO () |
175 | | evaluate x = IO (\s -> case seq# x s of |
176 | | (# _, s' #) -> (# (), s' #) |
177 | | }}} |
178 | | |
179 | | All the same equations hold as with the old defn for `seq`, but the problems |
180 | | go away: |
181 | | * Problem 1: (seq x y) is elaborated in the desugarer |
182 | | * Problem 2: problem largely unaffected |
183 | | * Problem 3: if we regard `(seq# a b)` as expensive, we won't eta expand. |
184 | | * Problem 4: unchanged |
| 180 | |
| 181 | and if we consider `seq#` to be expensive, then we won't eta-expand around it, and that would fix problem 3. |
| 182 | |
| 183 | However, there is a concern that this might lead to performance regressions in examples like this: |
| 184 | |
| 185 | {{{ |
| 186 | f :: Int -> Int -> IO Int |
| 187 | f x y | x `seq` False = undefined |
| 188 | f x 3 = do |
| 189 | ... some IO monad code here ... |
| 190 | }}} |
| 191 | |
| 192 | so `f` turns into |
| 193 | |
| 194 | {{{ |
| 195 | f = \x . \y . case seq# x RW of (# _, x #) -> case y of 3 -> \s . some IO monad code |
| 196 | }}} |
| 197 | |
| 198 | and we won't get to eta-expand the `\s` as we would normally do (this is pretty important for getting good performance from IO and ST monad code). |
| 199 | |
| 200 | Arguably `f` should be rewritten with a bang pattern, and we should treat bang patterns as the eta-expandable seq and translate them directly into `case`, not `seq#`. But this would be a subtle difference between `seq` and bang patterns. |
| 201 | |
| 202 | Furthermore, we already have `pseq`, which is supposed to be a "strictly ordered seq", that is it preserves evaluation order. So perhaps `pseq` should be the one that more accurately implements the programmer's intentions, leaving `seq` as it currently is. |
| 203 | |
| 204 | We are currently pondering what to do here. |
| 205 | |