-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Don't re-calculate independent parameters #3
Comments
In v0.1, there are 3 ways
With these in mind, let:
Given these, there is only a limited number of ways
Deriving codefun <T> List<T>.permutations(): Sequence<List<T>> =
if (size == 1) {
sequenceOf(this)
} else {
this.asSequence().flatMapIndexed { i, first ->
val tail = subList(0, i) + subList(i + 1, size)
tail.permutations().map { tailPermutation ->
listOf(first) + tailPermutation
}
}
}
// If the elements appear in order, even with others separating them
fun <T> List<T>.inOrder(vararg elements: T): Boolean =
elements.asList()
.zipWithNext()
.all { (a, b) -> indexOf(a) < indexOf(b) }
listOf("aD", "bD", "aC", "bC", "aU", "bU").permutations()
.filter { it.inOrder("aD", "bD") } // a is declared before b
.filter { it.inOrder("aD", "aC", "aU") && it.inOrder("bD", "bC", "bU") } // declare -> calculate -> use
.filterNot { it.inOrder("aC", "bC", "aU", "bU") } // impossible for b's getValue() to start during a's, then end after
.filterNot { it.inOrder("bC", "aC", "bU", "aU") } // ^ and vice versa However, for every one of these possibilities, it is possible for one parameter to be dependent on the other (with examples under each if you expand them). This means that with the behavior in v0.1, it is impossible for |
Now instead, consider how it could work if arguments were immediately calculated upon Declaration. Probing when the argument is calculated is no longer part of This means all that needs to be considered is declaration ( This gives us 3 possibilities:
Deriving codefun <T> List<T>.permutations(): Sequence<List<T>> =
if (size == 1) {
sequenceOf(this)
} else {
this.asSequence().flatMapIndexed { i, first ->
val tail = subList(0, i) + subList(i + 1, size)
tail.permutations().map { tailPermutation ->
listOf(first) + tailPermutation
}
}
}
// If the elements appear in order, even with others separating them
fun <T> List<T>.inOrder(vararg elements: T): Boolean =
elements.asList()
.zipWithNext()
.all { (a, b) -> indexOf(a) < indexOf(b) }
listOf("aD", "bD", "aU", "bU").permutations()
.filter { it.inOrder("aD", "bD") } // a is declared before b
.filter { it.inOrder("aD", "aU") && it.inOrder("bD", "bU") } // declare -> use So, in the first two cases, |
There is one caveat, though I'm not sure how much of an issue it'd be. I can think of cases where an iterator postpones parameterize {
var bValue = -1
val a by parameter(
sequence {
yield(1)
yield(bValue)
}.asIterable()
)
val b by parameterOf(2, 3)
bValue = b
} Here, |
Currently an argument iterator is re-calculated when a previous parameter is iterated:
Will print:
Here
parameter2
is being calculated more than once, which may not be a lot here, but calculating once for every combination parameters before it could easily become tens of thousands of recalculations when only one is necessary.It behaves this way because parameterize cautiously assumes that iterating a parameter (
parameter1
) will require future parameters iterators to be re-calculated (e.g. ifparameter2
usedparameter1
)It's possible to track when parameters are declared and used, so it should be possible to see that
parameter2
is declared withoutparameter1
being used, soparameter2
does not need to be re-calculated after iteratingparameter1
's argument to'b'
.The text was updated successfully, but these errors were encountered: