I’m not sure how actively do we use Discussions bu...
# arrow-contributors
p
I’m not sure how actively do we use Discussions but I’m thinking about adding topics like these there instead of (or as well as) in here
r
I think here we can chat more fluidly but for something that is gonna remain as a feature then discussions for public archive is more appropiate
👍 1
I like the proposal but I think
takeMap
is not a good name for it.
take
is just an impl detail of this being a
zipOrNull
If you think of this as combining two applicative operations which is what zip does you have
list.zip(list2)
, if you are just zipping your own elements or returning null if a
zip
to self is not possible maybe this is
zipOrNull
or
zipToSelfOrNull
or whatever the std lib has as name to tuple the elements of a list
p
yeah, I agree, the name could do with a better candidate. I’m not sure it’s a zip though. Specially since
List
already has a zip It would be more like a reduce or fold right?
r
let me see if there is a name for this already
p
maybe
reduceN
?
Or
reduceOrNull
🤔
r
The std lib calls the tupling op
zipWithNext
p
I guess it makes sense to go with some time prefixed as zip if there is already a
reflective
zip
r
well the thing is that the std lib already has zipWithNext that takes a transform function
which is exactly this right?
p
oh wait, I just saw there is already a zipwithNext with a transformation
I’m not sure it’s quite the same though. As the idea is more about taking a number n of items and then folding them into a single final value.
zipWithNext
returns a list with the values calculated from adjacent elements
r
it would be the remaining arities that zipWithNext is missing if you extend the arity to triple and then to the tuples?
but this op as implemented in the standard lib just adds a function argument to avoid tupling
p
I’m thinking
foldN
may be more accurate as they would be:
Copy code
(List<A>, (A) -> R) -> R?
(List<A>, (A, A) -> R) -> R?
...
r
It’s a fold in its base because the empty element is null but to be consistent with the std lib is just new versions of
zipWithNext
where on each one an additional function argument is implemented
it’s the same case as we have with zip in arrow
the additional arities can be implemented in terms of map2 or zip
oh I see, nevermind, I think I missunderstood
sorry I missuderstood the original post example
I think it makes sense as takeMap since you are just taking the arguments and passing it to the function but no need to tuple them, the function is not executed
💯 1
p
Another option could be to have NEL1, NEL2, NEL3, etc with respective folds 🤔 So we can do
Copy code
list.take2()?.fold { a, b -> ... }
It would add an extra type in the middle but I can see other cases where having the size codified on the type could be useful, perhaps
Probably two different solutions though. Maybe this last one could wait for value classes as then we could potentially add these operations to them with Meta. Maybe for data classes too. 🤔 I may open a separate disc for this 😅
r
Is the overall problem you are trying to solve is that you have arguments on a list and list destructuring it’s unsafe so first you need to check for the values being there before you apply a function?
If that is the case the something like this may be relevant
this would prevent you from calling a function if the argument was not there and allows you to add more than 5 elements to destructuring
of course you’d have to replace the component1 explicit calls for checks on the argument to see if it’s actually there
I’ll update the example
p
Actually, we may not need the wrapper if we use nullable comprehensions:
Copy code
val result = nullable {
  val a = list.getOrNull(0).bind()  
  val b = list.getOrNull(1).bind()
  "$a $b"
}
When we get multiple receivers we could create something like
List.bindAt(index: Int)
I think there is room for both a n-arity solution like
DestructuredInvoke
as well as more concrete ones for small arities. Like:
Copy code
value class SingleList<T>(val first: T) {
  fun component1(): T = first
}
value class SingleList<T>(
  val first: T,
  val second: T,
) {
  fun component1(): T = first
  fun component2(): T = second
}
#futurefeature 😅
I had a brain session with my pillow last night and thought of a better solution… iteration comprehension:
Copy code
val result: Result<String> = list.iterating {
  val a = next()
  drop(2)
  val c = next()
  "$a $c"
}
More flexibility and infinite arity 😅 I’m open to better names though 🙂
r
That blows up if the iterator is empty?
p
It would return a
Result
with an exception in it. Initially I thought we could return a
null
but I thought that this way we can communicate where the error happened. And then people can decide to convert to a null or handle the exception. The downside is that we would be throwing an exception. Alternatively, we could have
iteratingOrNull
that skips the exception throwing if it’s not needed. Btw, the
next()
is not the next from
Iterator
but rather a function defined in the receiver scope of
iterating
forgot to mention 😅
Maybe could also have an
iteratingOrEither
for non exception handling of the result 🤔 Problem here is that we have to create wrapper. Or maybe have the default return an Either and then the user can convert it to a Result if they need to. Open to any of these options or all at the same time, not sure what’s best 🙂
r
Iterator comprehensions would be if multishot was being bind, but it does not, this is something else. In whatever case we could not introduce an idiom that throws exceptions as none of our other blocks or API do
if you have a gist compiling I’d like to take a look
p
Just in my head for now 🙂 But yeah, probably two impls that returns
Either<IterateError, T>
or
null
respectively may be the best solution. A wrapper (Either) is probably better than throwing an exception for sure. I’ll see if I get some time this week to try something
r
thanks, looking forward to checking it out!
👍 1