Open creese opened 11 years ago
Unfortunately, ->
is invalid variable name in python, so you can't do anything that looks like clojure thread macros ->
and ->>
. By the way, it's easy to read only in s-expression
notation. But definitely, we can have something like
F(x) >> foo >> bar >> baz
F
is not good name for such use case, pipe
is more appropriate, I think.
pipe(x) >> foo >> bar >> baz
The only one problem that I see, is that python is strictly evaluated and we need to decide on each reducing step what to do: keep going with new functions or evaluate final result. Possible, we need something like "sentinel" function to execute whole pipe:
pipe(x) >> foo >> bar >> baz >> end
or
pipe(x) >> foo >> bar >> baz >> result
or even
pipe.start(x) >> foo >> bar >> baz >> pipe.end
What do you think about such syntax? Can you give a shining example where it's useful?
A lot of my methods tend to look like:
def func(x):
f = F() >> foo >> bar >> baz
return f(x)
Lately, I've begun to work with just functions. It feels more Pythonic.
def func(x):
f = compose(foo, bar, baz)
return f(x)
or even,
def func(x):
return thread_last(x, foo, bar, baz)
creese, where is the above compose
function from?
By the way, how is this little sugar for pipe
/compose
? (I will call it pipe
for now.)
from fn.func import F
from fn.iters import first, rest
def pipe(*funcs):
def _pipe(*args, **kwargs):
return reduce(lambda f, g: f >> g,
rest(funcs),
F(first(funcs), *args, **kwargs))()
return _pipe
Some examples to follow
from functools import partial
from operator import add, mul
inc = partial(add, 1)
double = partial(mul, 2)
triple = partial(mul, 3)
double_triple_inc = pipe(double, triple, inc)
inc_double_triple = pipe(inc, double, triple)
assert double_triple_inc(2) == 13 # 2 * 2 * 3 + 1 = 13
assert double_triple_inc(3) == 19 # 3 * 2 * 3 + 1 = 19
assert inc_double_triple(3) == 24 # (3 + 1) * 2 * 3 = 24
and
from functools import partial
from operator import mul, neg
from random import random
rndm = pipe(random, partial(mul, 10), int, neg)
print([rndm() for i in range(10)]) # some random negative integers
Any thoughts?
EDIT: Fix neg
missing from the import statement.
Earlier today I had the crazy idea to do something like this by abusing some operators (or and invert):
mod_primes = ~(pipe(primes)
| filter(lambda a: a > 20)
| map(lambda a: a * a)
| zip_index
)
A simple implementation is at: https://gist.github.com/venuatu/0b35e331aeea9f3feb8f
Would this be a good addition for this library?
Your implementation refers to lists but it actually can work for any type, does'nt it?
Often, when I chain functions, I find myself using the following pattern:
(F() >> foo >> bar >> baz)(x)
If this were clojure, I could write:
(-> x foo bar baz)
Notice the input on the left. Is there any to way to do this in python/fn?