lo
lo copied to clipboard
Add Support for pipeline usage
like this
type Foo struct {
ID string
}
value := []*Foo{{ID: "a"}, {ID: "b"}, {ID: "c"}}
pipe := lo.NewPipeline(value)
result := pipe.Map(func(v *Foo) string { return v.ID }).Filter(func(v *Foo) bool { return v.ID == "a" }).Uniq().Result()
Hi @yxlimo and thanks for the proposal.
We already have some "mixed" helpers, such as MapFilter
. But I agree with you, we should have something more ambitious.
Unfortunately, Go does not offer method-level generics, for now. So you would need to declare every type from lo.NewPipeline
constructor.
I would suggest something like:
import "github.com/samber/lo/x
x.Pipe(
x.Map[Foo, string](...),
x.Filter[string](...),
x.Map[string, int](...),
x.Uniq[int](...),
)
With Pipe
doing some reflection for transmitting arguments over the functions. it can not be considered as safe, but it could be a good start until Go dev team add support for method-level generics.
WDYT?
Did you imagine a better workaround? 🤔
Maybe type-safe function (not method)
func Map[T, U any] (in *Pipe[T], cb func(T) U) (out *Pipe[U])
where Pipe
is proposed object with bunch of methods can be good workaround.
Maybe type-safe function (not method)
func Map[T, U any] (in *Pipe[T], cb func(T) U) (out *Pipe[U])
where
Pipe
is proposed object with bunch of methods can be good workaround.
Good idea but still not that easy to use, and I suppose it to be something like %>%
operator in R language.
Maybe here we should use .
operator but this can't come together with existing .
operator.
Your Pipe
is much like Stream
in java, I guess?
Actually this package is my first time experience of functional programming in Go language, it's great.
@xakep666 the prototype you propose is the same than the current lo.Map, lo.Filter... functions.
What should Pipe[T]
do in your example?
@xakep666 the prototype you propose is the same than the current lo.Map, lo.Filter... functions.
What should
Pipe[T]
do in your example?
My thoughts for example
type Pipe[T any] []T
func NewPipe[T any](source []T) *Pipe[T] {
pipe := Pipe[T](source)
return &pipe
}
func (p *Pipe[T]) Map[U any](f func(T,int) U) *Pipe[U] {
v := lo.Map([]T(*p), f)
return NewPipe(v)
}
// ... (other functions as pipe methods)
func (p *Pipe[T]) Get() []T {
return []T(*p)
}
@xakep666 the prototype you propose is the same than the current lo.Map, lo.Filter... functions.
What should
Pipe[T]
do in your example?
just wrap slices with pipes, and change functions into pipe methods, whose return type is pipe as well.
add methods to create pipe with exsisting slices and get results from a pipe.
@xakep666 the prototype you propose is the same than the current lo.Map, lo.Filter... functions.
What should
Pipe[T]
do in your example?
Oh, I forget that a method can't use generic...
Pipe
can be used to incapsulate lazy evaluations for example. Methods are similar to lo
package functions.
I'd link to streams design for this purpose http://nessos.github.io/Streams