I swear I have long covid and brain fog or somethi...
# getting-started
a
I swear I have long covid and brain fog or something. Is there an idiomatic way in Kotlin to
map
while supplying the map-like operation with a list of functions (or vararg) to apply to each element, rather than a single transformation? basically
collection.mapAll(transformers: List<(T) -> R>)
sequence.mapAll(transformers: List<(T) -> T>)
I want to supply a list of transformers so I don’t have to do something like:
Copy code
sequence.map(::first)
.map(::second)
.map(::third)
would be:
Copy code
sequence.map(tranformers)
j
I don't think there is any built-in stdlib function to do that directly. But you could implement your own. Note that
List<(T) -> R>
cannot work in general, though, because you would need each function's output type to be the same (or a subtype) of the next function's input type.
w
🤔 if you are mapping, you are changing the types, so I don't see this list of transformers working (how would the compiler ensure the types?)
1
Would
Sequence
not handle this case without having to make multiple iterations? 🤔
d
If I'm not mistaken there is a "common" rule: if you have more than 2 transform operators you'd better use a sequence.
a
I may be approaching the problem incorrectly. The input type in each transformer is the the same as the output. It’s basically like a reducer, but I keep each element. Each function has a responsibility to calculate some specific business rule and applies its value to an accumulator.
I am using a sequence.
I should change the “collection” to “sequence” in my example.
⬆️ 1
d
extension functions to the rescue :)
a
Ok. I thought there might be a way to just simply apply a list of functions with an argument, like a chain, where the output is the input of the next in the list.
j
If the types are all the same, one way to roll your own is the following:
Copy code
fun <T> Sequence<T>.map(transforms: List<(T) -> T>): Sequence<T> =
    transforms.fold(this) { s, t -> s.map(t) }
See: https://pl.kotl.in/clSuDg4m0
👌 1
a
hah. thanks.
j
Note that this
fold
is not operating on the sequence, but on the list of transformations, so it builds a new sequence by repeatedly applying
map
with each transform. The initial value for the fold is the initial sequence.
a
hmmm. I’ll have to think about that one.
Thanks all for info. At least I know there isn’t a “native” way to apply this. Again, I am pretty sure I might be doing something “wrong”, but I am just working on a PoC for extracting and reporting on data from an external system in a concise and extensible way to supply new functionality without modifying the execution code.
And I wasn’t kidding about the brain fog. It’s like I used to be able to play chess, think a few moves ahead, and now I can only imagine one or two. It’s odd. Hah. All the caffeine in the world doesn’t help.
🥲 2
BTW, I also fixed the signature as it was wrong: It should have always been:
(T) -> T
not
(T) -> R
(for my example)
k
Another way:
Copy code
sequence.map {
    it.let(::transform1)
        .let(::transform2)
        .let(::transform3)
}
This also works just as well with collections, as it transforms it element-by-element.
a
I need to pass a collection of functions. The list is unknown until it’s executed.
e
you could fold over the transforms while mapping each individual element,
Copy code
fun <T> Sequence<T>.map(transforms: Iterable<(T) -> T>): Sequence<T> = map {
    transforms.fold(it) { s, t -> s.map(t) }
}