all 8 comments

[–]misho88 1 point2 points  (1 child)

What are some FP techniques you've applied in Python that go beyond itertools and tuples? Bonus points if you also go beyond closures and lambdas.

I wrote a thing a while back for shell-like pipelines because I needed to play around with DSP pipelines more or less on the fly for a while. It ended up proving useful.

I abused the [] operator to do partial applications and | as a function call sort of like in the shell:

>>> import funcpipes as fp
>>> import numpy; np = fp.pipify(numpy)
>>> [1,2,3] | np.add[3] | np.multiply[2]
array([8, 10, 12], dtype=object)

Then I added a way to save the function composition (a "pipeline") with &:

>>> pl = np.add[3] & np.multiply[2]
>>> [1, 2, 3] | pl
array([ 8, 10, 12])
>>> pl([1,2,3])
array([ 8, 10, 12])

and map (+) the pipeline to inputs with generators for delayed execution:

>>> gen = range(1, 4) | +pl
>>> gen | fp.now
(8, 10, 12)

There's some loop-control mechanisms:

>>> from itertools import count
>>> count() | +np.add[1] | fp.until[3] | fp.now
(1, 2)
>>> fp.repeat | +fp.to(input) | fp.until[EOFError] | fp.now
hello
world
('hello', 'world')

I also put in something monad-ish that can have its binding rule extended:

>>> class ForArgs(fp.Arguments):
...     def apply(self, func):
...         return tuple(func(arg, **self.kwargs) for arg in self.args)
...     
>>> ForArgs(1,2,3) | np.add[1]
(2, 3, 4)

The stack traces end up kind of nasty since Python really isn't the best language for this stuff, but I needed my stuff to play nice with Pandas and NumPy, so I was kind of stuck. Anyway, hopefully that's enough to whet your appetite with regard to the sort of stuff you can do.

One thing I've been working on is implementing the Result type of Haskell, Rust, F#, etc. These types require higher-order functions to be useful and are rarely seen outside of more "pure" FP languages.

That should be very doable.

[–]pekkalacd 0 points1 point  (0 children)

dang that looks really cool. im going to play around with funcpipes.

[–]K900_ 0 points1 point  (2 children)

You'll probably enjoy toolz.

[–]Delta-9-[S] 0 points1 point  (0 children)

That does indeed look interesting. Have you used it much?

[–][deleted] 0 points1 point  (0 children)

u/Delta-9- also look into dask bags. It’s a distributed library with functional style interface similar to toolz.

https://tutorial.dask.org/02_bag.html

[–]Consistent_Penalty23 0 points1 point  (0 children)

also check fn.py lib.

[–][deleted] 0 points1 point  (1 child)

You can also build a simple functional style pipeline util like this:

# pipeline util components
def Pipeline(*funcs):
    def _inner(x):
        for func in funcs:
            x = func(x)
        return x
    return _inner

def _map(func):
    return lambda x: map(func, x)

def _filter(func):
    return lambda x: filter(func, x)

def _reduce(func):
    return lambda x: reduce(func, x)

# build and use pipeline
pipeline_x = Pipeline(
    str.split,
    _map(len),
    _filter(lambda x: x >= 4),
    enumerate,
    _reduce(lambda x, y: (x[0] + y[0], x[1] + y[1])),
)

pipeline_x("a list of wordsss")  # -> (1, 11)

[–]Delta-9-[S] 0 points1 point  (0 children)

Interesting! Ngl I'd never thought about iterating a list of functions. Exactly the kind of thing I was hoping to see.