| | 31 | The idea is to flatten out the processing of comprehensions to some degree by defining a transformation function `<< . >>` that gets two arguments: a pattern `pa` and a desugared expression `ea`, where we are guaranteed that `ea` is array valued and all its elements match `pa`. The semantics of the transformation function is given by |
| | 32 | {{{ |
| | 33 | <<[: e | qs :]>> pa ea = [: e | pa <- ea, qs :] |
| | 34 | = concatMap (\pa -> [: e | qs :]) ea |
| | 35 | }}} |
| | 36 | We have the second line by applying Rule (3). |
| | 37 | |
| | 38 | Using this definition of `<< . >>`, we can derive a new set of desugaring rules. The derivation proceeds by unfold/fold transformations and some properties of the involved combinators. The resulting rules are the following: |
| | 39 | {{{ |
| | 40 | (1') <<[: e | :]>> pa ea = mapP (\pa -> e) ea |
| | 41 | (2') <<[: e | b, qs :]>> pa ea = |
| | 42 | <<[: e | qs :]>> pa (filterP (\pa -> b) ea) |
| | 43 | (3') <<[: e | p <- a, qs :]>> pa ea = |
| | 44 | let ok p = True |
| | 45 | ok p = False |
| | 46 | in |
| | 47 | <<[: q | qs :]>> (pa, p) (crossMapP ea (\pa -> filterP ok a)) |
| | 48 | (4') <<[: e | let ds, qs :]>> pa ea = |
| | 49 | <<[: e | qs :]>> (pa, XS) (mapP (\v@pa -> let ds in (v, XS)) ea) |
| | 50 | where XS are the variables bound by ds |
| | 51 | (5') <<[: e | qs | qss :]>> pa ea = |
| | 52 | <<[: e | qss :]>> (pa, XS) (zipP ea [: XS | qs :]) |
| | 53 | where XS are the variables bound by qs |
| | 54 | }}} |
| | 55 | The typical array processing comprehensions containing only generators, guards, and parallel comprehensions (but not cross-products and lets) are translated into a straight combination of `mapP`, `filterP`, and `zipP` by these rules, which is exactly what we want. |