-
Notifications
You must be signed in to change notification settings - Fork 263
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
The "collect" decorator #557
Comments
This seems like a really worthwhile ergonomics boon. If I was the maintainer of Goes well with #486 - if the I'm imagining Could maybe even enhance the |
I decided to add a PR in case you decide to add it to |
So... I'm not a big fan. In my mind, the functional style of programming is about separating the "business" logic from the iteration logic that feeds them data. These decorators encourage people to stop before achieving such separation. consider the following:@curry
def raise(powers, entry):
power = powers.get(entry)
return entry ** power if power is not None and power >= 0 else None
def to_power(powers):
return compose_left(
map(raise(powers))
, remove(identity)
, list
) def reverse_mapping(expensive_func):
return compose_left(
map(juxt(expensive_func, identity))
, dict
, keyfilter(identity)
) |
@ZeroBomb for what it's worth, I find your first alternative harder to understand than either the manual list-appending version or this "collect into list" decorator proposal. (I had the luck of trying to understand your alternatives from a clean slate, because I totally forgot the examples from the beginning of this issue.) The biggest reason is that the relevant information gets spread out further apart and I feel myself having to think and remember more across the two functions to re-connect it. |
I suggest looking at this proposal more abstractly:
|
@mentalisttraceur you're reading my mind! @ZeroBomb @collect
def interpolate_dict(slices, size, default):
for index in range(size):
# find_nearest_keys's contents are not relevant for the example
start, stop = find_nearest_keys(slices, index)
if index in slices:
yield slices[index]
elif start is not None and stop is not None:
try:
# interpolate's contents are not relevant for the example
yield interpolate(slices[start], slices[stop], (index - start) / (stop - start))
except InterpolationError:
yield default
else:
yield [] Here you could do some comprehensions and exceptions rerouting and maybe define a tiny function that calls |
So I will admit to writing decorators like the ones in this proposal in the past, but ultimately I would end up removing them because I was using them in ways that ended up being counter-productive. The pattern I observed in my own coding would go like this:
In @maxme1 's example, I would gravitate towards something like this: @curry
def interpolate_index(slices, index, default=None):
# business code, and nothing but.
# This describes exactly the process for calculating the interpolated value at an index
if index in slices:
return slices[index]
start, stop = find_nearest_keys(slices, index)
if start and stop:
try:
return interpolate(slices[start], slices[stop], (index - start) / (stop - start))
except InterpolationError:
return default
return []
def interpolate_dict(slices, size, default=None):
# This describes the process for interpolating over a range of values
return map(interpolate_index(slices, default=default), range(size))
# More generally
def apply_interpolator(interpolator, size):
# This describes the process for interpolating over a range of values
return map(interpolator, range(size)) There is a sense in which you have to keep two things in mind (the mapping function and the mapped function), but I would argue that:
|
Isn't writing code like this a bit too much of future-proofing? But I see your point. You're basically saying that decorators like these are against the philosophy of @ZeroBomb @mentalisttraceur maybe you could suggest another package where this functionality will fit? |
Thanks for the feedback, everyone! |
Hi!
I often encounter the same pattern in my code:
The examples are somewhat simplistic, but you get the idea:
I came up with several decorators that reduce this to:
composed(func)
simply appliesfunc
to the result of the decorated function, which effectively gathers the generator. Andcollect
is just a shorter version ofcomposed(list)
I can create a PR with my implementation, if you are interested in adding it to toolz.
The text was updated successfully, but these errors were encountered: