5 | | ~~[: e | :] ~~ = [:e:] |

6 | | [: e | b, qs :] = if b then [: e | qs :] else [::] |

7 | | [: e | p <- a, qs :] = let ok p = [: e | qs :] |

8 | | ok _ = [::] |

9 | | ~~in concatMap~~ ok a |

10 | | [: e | let ds, qs :] = let ds in [: e | qs :] |

11 | | [: e | qs | qss :] = |

12 | | ~~ ~~ [: e | (XS, XSS) <- zip [: XS | qs :] [: XSS | qss :] :] |

13 | | where XS & XSS are the bound variables in qs & qss |

| 5 | (1) [: e | :] = [:e:] |

| 6 | (2) [: e | b, qs :] = if b then [: e | qs :] else [::] |

| 7 | (3) [: e | p <- a, qs :] = let ok p = [: e | qs :] |

| 8 | ok _ = [::] |

| 9 | in concatMapP ok a |

| 10 | (4) [: e | let ds, qs :] = let ds in [: e | qs :] |

| 11 | (5) [: e | qs | qss :] = |

| 12 | (6) [: e | (XS, XSS) <- zip [: XS | qs :] [: XSS | qss :] :] |

| 13 | where XS & XSS are the bound variables in qs & qss |

| 15 | In particular, `concatMapP f a` essentially implies to apply the lifted version of `f` directly to `a` and then the concat strips of one level of segment descriptors; i.e., both the `concatP` and the `mapP` vanish due to vectorisation. |

| 16 | |

| 17 | == Problem with the naive rules == |

| 18 | |

| 19 | Nevertheless, these rules are not entirely satisfactory. For example, `[:e | x <- a, b:]` turns into |

| 20 | {{{ |

| 21 | concatMap (\x -> if b then [:e:] else [::]) a |

| 22 | }}} |

| 23 | which is a fairly complicated way to perform |

| 24 | {{{ |

| 25 | mapP (\x -> e) . filterP (\x -> b) $ a |

| 26 | }}} |

| 27 | even when taking vectorisation into account. Under vectorisation, the conditional implies `filterP (\x -> b)`, but adds an expensive, and here useless, merge operation. Maybe these overheads can be optimised away. However, for the moment, we use a desugaring that is based on the above rules, but generates code that should be better suited to array processing. |

| 28 | |

| 29 | == Modified rules == |

| 30 | |