However, there is no currying. I'm sad. So I wrote a curry function that counts the positional arguments by myself.
First, I wrote a function composition. It's simple and shabby.
def compose(*funcs: Callable) -> Callable:
'''
>>> compose(multest, multest)(4)
16
'''
def composed(*args: Any) -> Any:
return reduce(lambda x, y: y(x), (funcs[0](*args),)+funcs[1:])
return composed
The mechanism is as simple as checking the number of positional arguments and partially partialing that much. So sometimes it doesn't work.
def _curry_one(func: Callable) -> Callable:
def wrap(*args: Any, **kwargs: Any) -> Any:
return partial(func, *args, **kwargs)
return wrap
def curry(num_of_args: Optional[int] = None) -> Callable:
'''
>>> fnc = curry(2)(multest2)
>>> fnc(2)(3)
6
>>> fnc = curry()(multest3)
>>> fnc(2)(3)(4)
24
'''
def curry_wrap(func: Callable) -> Callable:
length_of = compose(filter, list, len)
if num_of_args:
num = num_of_args
else:
def is_empty(x): return x.default is inspect._empty
num = length_of(is_empty,
inspect.signature(func).parameters.values())
for n in range(num - 1):
func = _curry_one(func)
return func
return curry_wrap
This counts the number of arguments when currying, and curries as many as the number of positional arguments. You can also specify the number of times to curry. However, in practice, it is fixed at 2 and it feels good.
It can be partial, but this curry can be used as a decorator.
@curry()
def test(x, y, z):
return x * y + z
Also, sometimes useful when using it as a higher-order function. Mainly when it is necessary to separate cases When I have to bring out a starmap. For example, I can't read the last part below. (Write)
def plus(x, y):
return x * y
result = list(map(partial(plus, 3), range(4)))
This guy's partial can be separated.
def plus(x, y):
return x * y
plus3 = partial(plus)
result = list(map(plus3, range(4)))
The namespace is a little bit ... I feel uncomfortable with more plus hoge. I can write this guy like this
@curry()
def plus(x, y):
return x * y
result = compose(map, list)(plus(3), range(4))
It's decided to be useless, python should be the same no matter who writes it. Therefore, the above should not be used.
Dissolution
Use numpy in your personal project. I'm self-employed, but I was disappointed because I couldn't read the code because I wrote the code like this.
np.save(fname, baseline(np.square(fft(data.mean(axis=1)))))
This is a scientific calculation package, so there is room for consideration in the situation (is there?). There were so many math variables and the namespace was crazy ... If there was currying and function composition here, this would be the case, right?
mean = curry(np.mean)
save = curry(np.save)
compose(mean(axis=1), fft, np.square, np.std, save(fname))(data)
... isn't it? Personal project acquittal.
Recommended Posts