Python's list-comprehensions are incredibly useful, since they allow us to write common patterns into the simple, concise, very readable one-liners:
loop with filter | loop with break |
---|---|
l = [] for x in xs: if g(x): l.append(f(x)) |
l = [] for x in xs: if not g(x): break l.append(f(x)) |
[f(x) for x in xs if g(x)] |
[f(x) for x in takewhile(g, x)] |
Consider the slightly more general patterns of allowing the filter/break to depend on all previously generated elements:
loop with history-dependent filter | loop with history-dependent break |
---|---|
l = [] for x in xs: if g(x, l): l.append(f(x)) |
l = [] for x in xs: if not g(x, l): break l.append(f(x)) |
Question: Is it at all possible to translate these patterns into list-comprehensions as well?
To me, it seems the answer is no / it is only doable for very special cases of g
(like [1]), because in one would need to be able to reference the list as it being created.
End of the question // Some incoherent rambling:
It seems that one would need a completely new syntax along the lines of
[f(x) for x in xs if g(x, this)]
Where this
is a symbolic placeholder for a new keyword that would one to reference the outer object from within a context. I have no idea if this is even in principle possible at all, but it would be kinda cool to be able to write
loop with history-dependent filter | loop with history-dependent break |
---|---|
l = [] for x in xs: if g(x, l): l.append(f(x)) |
l = [] for x in xs: if not g(x, l): break l.append(f(x)) |
[f(x) for x in xs if g(x, this)] |
[f(x) for x in xs while g(x, this)] |
Or the even more general
loop with history-dependent filter and yield | loop with history-dependent break and yield |
---|---|
l = [] for x in xs: if g(x, l): l.append(f(x, l)) |
l = [] for x in xs: if not g(x, l): break l.append(f(x, l)) |
[f(x, this) for x in xs if g(x, this)] |
[f(x, this) for x in xs while g(x, this)] |
Where both the next element and the exit condition of the list comprehension are allowed to depend on all previously generated elements. In set-builder notation, the two constructs would translate to
S⁽ⁿ⁺¹⁾ = { f(xₖ, S⁽ᵏ⁾) ∣ xₖ∈{x₁,…,xₙ} ∧ g(xₖ, S⁽ᵏ⁾) }
= S⁽ⁿ⁾ ∪ {f(xₙ, S⁽ⁿ⁾) ∣ g(xₙ, S⁽ⁿ⁾)}
and
S⁽ⁿ⁺¹⁾ = { f(xₖ, S⁽ᵏ⁾) ∣ xₖ∈{x₁,…,xₙ} ∧ ∀l≤k g(xₗ, S⁽ˡ⁾) }
= S⁽ⁿ⁾ ∪ {f(xₙ, S⁽ⁿ⁾) ∣ ∀k≤n g(xₖ, S⁽ᵏ⁾)}
Are there any languages out there that have a feature like this?