dbrattli / Expression

Functional programming for Python
https://expression.readthedocs.io
MIT License
475 stars 31 forks source link

Seq and generators #56

Closed jim108dev closed 2 years ago

jim108dev commented 2 years ago

Hi!

Is there a way to map over generators? Can seq help? For example:

YEARS:List[int] = [2015, 2016, 2017, 2018, 2019, 2020, 2021]

def get_train_test_years():
    for i in range(3, len(YEARS)):
        yield YEARS[:i], YEARS[i]

def transform(x,y):
    return x+"Arbitrary complex",y+"Arbitrary complex"

#Does not work
ys = pipe(get_train_test_years(),
    seq.map(transform)
)

# works but repetitive
test_train_candidates  = (transform(train_years, test_year) for train_years, test_year in get_train_test_years())

Thanks!

dbrattli commented 2 years ago

The generator is not the problem. The problem is that your transform function takes two arguments. So you need to star the tuple argument:

ys = pipe(get_train_test_years(), seq.map(lambda x: transform(*x)))

But we should probably just add a starmap operator to the seq module:

def starmap(
    mapper: Callable[[Tuple[Any, ...]], Any]
) -> Callable[[Iterable[Any]], Iterable[Any]]:
    return seq.map(lambda x: mapper(*x))
jim108dev commented 2 years ago

At

ys = pipe(get_train_test_years(), seq.map(lambda x: transform(*x)))

I get

(parameter) x: TSource@map
"object*" is not iterable
"__iter__" method not definedPylance
dbrattli commented 2 years ago

Yes, lambdas do not support type annotations. Use a function instead so you can specify the type of x e.g:

def mapper(x: Tuple[List[int], int]):
    return transform(*x)

ys = pipe(get_train_test_years(), seq.map(mapper))

PS: Also add type annotations to transform.

jim108dev commented 2 years ago

Thanks for explaining this to me.