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

reader monad usage #37

Closed
galen1090 opened this issue Dec 8, 2019 · 6 comments
Closed

reader monad usage #37

galen1090 opened this issue Dec 8, 2019 · 6 comments
Labels
question Further information is requested

Comments

@galen1090
Copy link

I'm totally new of functional programming, I'm trying to use a reader monad to get rid of passing a lot of function parameter in my code, but I don't understand how to use it properly. Here a very simple use case.

def process(item, c):
    # how to get Connection?
    print(item, c)


def process_all() -> Reader[Connection, str]:
    def _(c):
        for item in range(5):
            process(item, c)
        return value("result")

    return ask().and_then(_)


def main():
    connection = Connection(URI='testuri')
    result = process_all().run(connection)
    print(result)

how can I get Connection in the process function without explicitly passing it? If I must pass it then I don't understand the advantage to directly pass Connection through functions without using a reader monad. What I'm missing?

Thanks.

@suned
Copy link
Owner

suned commented Dec 9, 2019

I often find that eliminating "plumbing" parameters with Reader is most effective when you ask for the reader value close to where you need it. In your example I would probably do something like

from pfun.reader import map_m, Reader, ask

def main():
    connection = Connection(URI='testuri')
    result = process_all().run(connection)
    print(result)


def process_all() -> Reader[Connection, str]:
    return map_m(process, range(5)).map(lambda _: 'result')


def process(item: int) -> Reader[Connection, None]:
    return ask().map(lambda c: print(item, c))

map_m is sort of like the built-in map except it expects a function that returns a Reader and will combine the results of mapping process over range(5) using and_then.

Reader.map applies its function argument to the "wrapped" Reader value, which in the case of the reader returned by ask happens to be the Connection instance.

@suned
Copy link
Owner

suned commented Dec 9, 2019

I apologize that I don't talk about map in the guide on readthedocs :)
I think the documentation still has a way to go before its super beginner friendly.

@suned suned added the question Further information is requested label Dec 9, 2019
@suned
Copy link
Owner

suned commented Dec 9, 2019

Maye sequence is a little more pythonic in this case:

from pfun.reader import sequence, Reader, ask

def process_all() -> Reader[Connection, str]:
    return sequence(process(i) for i in range(5)).map(lambda _: 'result')

@galen1090
Copy link
Author

Thanks, so if I want to do some stuff with a result coming from process I can do something like:

def process_all() -> Reader[Connection, List[int]]:
    def process_results(r):
        return list(map(lambda x: x*2, r))

    return map_m(process, range(5)).map(process_results)


def process(item: int) -> Reader[Connection, int]:
    def _(c):
        # do stuff
        return item
    return ask().map(_)

@galen1090
Copy link
Author

Another question :), if I want to use the Writer Monad together with Reader Monad:

def process(item: int) -> Writer[Reader[Connection, int], List[str]]:
    mylog = []
    def _(c):
        # do stuff
        mylog.append('test log')
        return item*2
    return Writer(ask().map(_), mylog)

connection = Connection(URI='testuri')
result, log = process(4).map(lambda x: x.run(connection))
print(log)
print(result)

there is a better way to do it? It seems a little ugly to me, and it's a very simple example.

@suned
Copy link
Owner

suned commented Dec 9, 2019

Thanks, so if I want to do some stuff with a result coming from process I can do something like

Exactly!

Another question :), if I want to use the Writer Monad together with Reader Monad

This is normally referred to as effect composition, and no, its not very nice. In other frameworks you'll find special constructs for dealing with this (monad transformers e.g). For pfun I'm working on another approach which will be released beginning of 2020

@suned suned closed this as completed Dec 11, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants