IBM / fp-go

functional programming library for golang
Apache License 2.0
1.6k stars 49 forks source link

Is there any `next`, `any` function similar to python? #77

Closed baagod closed 10 months ago

Carsten-Leue commented 10 months ago

Hi @baagod I assume you are referring to https://docs.python.org/3/library/functions.html#any and https://docs.python.org/3/library/functions.html#next

Both of these functions operate on python iterables, i.e. the abstract concept of a (potentially unbounded) sequence. In Golang such an abstraction does not exist, in idiomatic go you would have to create a channel to represent such sequences.

However I find that sometimes it can be helpful to have this abstraction. The package https://github.com/IBM/fp-go/blob/main/iterator/stateless contains an implementation of iterators in go. In contrast to Python iterators they are stateless, i.e. each step of the iteration creates a new iterator for the next step and the next value instead of modifying the current iterator. This is more in line with functional concepts.

For such an iterator the any function can be implemented as:

    return F.Flow3(
        Filter[GU](pred),
        First[GU],
        O.Fold(F.ConstFalse, F.Constant1[U](true)),
    )

Next is part of the iterator pattern, anyway.

Triggered by your question I have added the function Any as convenience, please check for an example for both Any and Next here:

https://github.com/IBM/fp-go/blob/main/iterator/stateless/example_test.go#L26

Question: what is your usecase?

baagod commented 10 months ago

I really feel like your detailed explanation. Actually, I just wanted to find a similar method to operate slicing, but I didn't seem to find it in the 'array' package:

func Any[T any](v []T, fn func(int, T) bool) bool {
    for i, x := range v {
        if fn(i, x) {
            return true
        }
    }
    return false
}

// python's next
func Find[T any](v []T, fn func(int, T) bool) (result T, ok bool) {
    for i, x := range v {
        if fn(i, x) {
            return x, true
        }
    }
    return
}

Sorry, I didn't make it clear in my question. I will make it clear in the future.

CarstenLeue commented 10 months ago

Hi @baagod indeed I did not have these operations in the array package explicitly.

One way to represent them would be

Any := F.Flow2(
        Filter(pred),
        IsNonEmpty[int],
    )

and

Find := F.Flow2(
        Filter(pred),
        Head[int],
    )

But it does make sense to have the operations reflected explicitly. Please check out the new functions Any and FindFirst in the array package and the example https://github.com/IBM/fp-go/blob/main/array/example_any_test.go and https://github.com/IBM/fp-go/blob/main/array/example_find_test.go

Is this what you were looking for?

I was actually surprised I missed to implement these functions, apparently the usecase has not appeared in my previous projects. Just out of curiosity, what's the usecase behind a need for these functions?

baagod commented 10 months ago

@CarstenLeue Thank you. I admire your attitude towards questioning. I can't think of too many cases at the moment. Suppose there is a group of users: 'list=[admin (10), admin (10)]', and you need to query whether a user is included in the list:

isFind = any(list, func() { return a.id == 10 })

If found, return to user:

admin10 = findFirst(list, func() { return a.id == 10 })

Although it may not necessarily be implemented in this way, it feels like it will always be useful. Just like 'any' and 'next' in Python, the difference is that they are iterators.

CarstenLeue commented 10 months ago

Hi @baagod I was asking because depending on what you do with the result, maybe a Filter or FilterMap operation would be an efficient alternative.

But anyway, thanks to your question we have these methods for arrays and iterators, now.

baagod commented 10 months ago

@CarstenLeue ok。

{593A8DA9-85C5-448C-A7B6-785F7FC747C7}