Skip to content
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

Add new side_effects function #122

Merged
merged 4 commits into from
Jan 15, 2014
Merged

Add new side_effects function #122

merged 4 commits into from
Jan 15, 2014

Conversation

mrocklin
Copy link
Member

@mrocklin mrocklin commented Jan 7, 2014

Large scale feedback on this would be appreciated. I suspect that there is probably a better way to accomplish this.

In general the goal is to provide a mechanism to support side effects. I suspect this is the watered down version of the core idea behind monads.

Mostly I suspect this to be used with debugging, e.g.

>>> seq = "Alice", "Bob", "Charlie", ...
>>> seq = side_effects(lambda item: print("working on " + str(item)), seq) 
>>> result = do_work_on(seq)
working on Alice
working on Bob
working on Charlie
...
>>> 

@mrocklin
Copy link
Member Author

mrocklin commented Jan 7, 2014

Whoops. I pushed this to the pytoolz/toolz repo, not mrocklin/toolz. Will clean up after merge.

@mrocklin
Copy link
Member Author

mrocklin commented Jan 7, 2014

Interstingly this might be related to the traced project @eriknw was working on in #69

In that case we want to cause some side effect whenever a function is called. I wonder if we should have a side_effects_seq and a side_effects_func. Trace's application of writing inputs and outputs to a specific file is only one thing we might want to do. A general version of this might be helpful.

@mrocklin
Copy link
Member Author

I've moved this to the sandbox. Merging tomorrow if no comments.

@eriknw
Copy link
Member

eriknw commented Jan 15, 2014

My abbreviated two cents: this is short enough, simple enough, and may have more applications than I can currently think of, so go ahead and add it. To graduate from sandbox back to itertoolz, I'd like to see more documentation or examples that go beyond debugging... or I just need more time to use it and become familiar with it, because it may be perfectly justified as primarily a debugging or logging tool. As it is, it is quite easy to use!

I think we may come up with a different (not necessarily better) function if we try to come up with additional examples. I saw when this PR was created and you asked for feedback, but, well, I haven't had much feedback to give. The function is simple enough, but it also feels related to "tee", "dup", monads, etc., which makes me wonder if there are other, more general ways to go about this.

By the way, it looks like you didn't remove side_effects from itertoolz when you added it to sandbox.

Regarding tracing of functions, yes, I still want to develop a way to easily perform tracing using a user-provided function. We can continue that discussion elsewhere, and I think a similar side_effect function for functions may be viable. I will think on it.

@mrocklin
Copy link
Member Author

Thanks for the feedback. I agree that there is probably a better more general way to go about this. It feels like it's close to something very useful. I think it's a good candidate for the sandbox. Hopefully with use it will become clear what that very useful thing is.

mrocklin added a commit that referenced this pull request Jan 15, 2014
Add new `side_effects` function
@mrocklin mrocklin merged commit 175f960 into master Jan 15, 2014
@mrocklin
Copy link
Member Author

Merged into sandbox

@mrocklin mrocklin deleted the side-effects branch January 15, 2014 17:31
@eriknw
Copy link
Member

eriknw commented Jan 15, 2014

Interestingly, funcy.debug has a tap function that is similar to side_effects, but is specific for printing:

def tap(x):
    print(x)
    return x

It also has log_calls, which provides rudimentary function tracing.

I don't this we should copy these, but it does show that somebody else found them appropriate to add to a library (but just because it's in a library doesn't mean it's useful).

A more general function may be more similar to compose and pipe in that it accepts a data element and returns a tuple of the output of multiple functions: (f(el), g(el), h(el)). I'm just playing around, but here's an example:

def foo(*funcs):
    def inner(*args, **kwargs):
        return tuple(f(*args, **kwargs) for f in funcs)
    return inner

def identity(x): return x
def double(x): return 2*x
def triple(x): return 3*x

Thus:

>>> combo = foo(identity, double, triple)
>>> combo(1)
(1, 2, 3)
>>> first(combo(1))
1

It's more involved, but it follows the tradition of composing functions instead of applying hidden functions to iterables. Just a thought.

@mrocklin
Copy link
Member Author

I think putting something to support debugging into toolz is reasonable. If it's possible to find something that factors out the debug application though then I think that that's preferable. For example I would define tap in the following way:

def tap(func, x):
    func(x)
    return x

I think that what you're proposing in foo is more similar to map than to compose. Maybe something like the following?

def funcmap(funcs, arg):
    result = []    
    for func in funcs:
        result.append(func(arg))
    return result

This is similar to map but there is an iterable of functions rather than an iterable of arguments.

Or the following

def funcmap(funcs, arg):
    return map(lambda f: f(arg), funcs)

@mrocklin
Copy link
Member Author

Oh, I like this tap now. It might be better than side_effects because

side_effects(foo) == map(tap(foo))
side_effects_func(foo, func) == compose(tap(foo), func, tap(foo))

where foo might be something like print

@mrocklin
Copy link
Member Author

I might rename tap to do though (my version of tap, not funcy's)

@eriknw eriknw mentioned this pull request May 16, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants