TE
TechEcho
Home24h TopNewestBestAskShowJobs
GitHubTwitter
Home

TechEcho

A tech news platform built with Next.js, providing global tech news and discussions.

GitHubTwitter

Home

HomeNewestBestAskShowJobs

Resources

HackerNews APIOriginal HackerNewsNext.js

© 2025 TechEcho. All rights reserved.

Functional Programming in Python

145 pointsby bearzooalmost 5 years ago

21 comments

rzimmermanalmost 5 years ago
I do hope Python keeps incorporating more of the &quot;good stuff&quot; from functional programming. List&#x2F;dict&#x2F;set comprehensions make code better - I can look at something and see very clearly that it&#x27;s correct. Type hinting is a great compromise between beginner&#x2F;quick scripting needs and offering a fully-baked type system. Type hints do a lot more than most people expect - you can create useful compound and custom types (like Tuple[Int, Str, Iterable]). If we can get some pattern matching in there I&#x27;m not sure what I&#x27;d do. Spend less time debugging test failures I guess. Not sure what I&#x27;d do with that time. Maybe see my family or learn how to bake pastry. Or finally clean the top of the stove. Or just write more Python in the same amount of time? I don&#x27;t know. Pattern matching.<p>Cool library, though.
评论 #23344812 未加载
评论 #23343107 未加载
ianhornalmost 5 years ago
This is neat. It reminds me of an silly project [0] I made a while back to implement do-notation in python. In OP&#x27;s project you still end up with code that&#x27;s basically this:<p><pre><code> y = (Maybe(just=x) if x &gt; 0 else Maybe()).bind(lambda a: Maybe(just=x*a) .bind(lambda b: Maybe.mreturn(a+b))) </code></pre> It&#x27;s functionally sound and standard, but ergonomically painful. I built a really fun horrible hack to allow you to write that instead as this:<p><pre><code> with do(Maybe) as y: a = Maybe(just=x) if x &gt; 0 else Maybe() b = Maybe(just=x*a) mreturn(a+b) </code></pre> It swaps out the assignment operator `=` in the `with do()` block for the monadic bind operation, which you might be used to seeing as `&lt;-`.<p>You just need to use my @with_do_notation decorator, which just completely rewrites your function using the ast library wherever it finds a block of `with do(SomeClass) as variable:`. I was even able to write ergonomically nice parser combinators [1] that would actually work pretty well if python had tail call optimization.<p>You shouldn&#x27;t use it but it was great fun and opened my eyes to the ways you can abuse python if you really wanted to. Using decorators to introspect and completely rewrite functions is a fun exercise.<p>[0] <a href="https:&#x2F;&#x2F;github.com&#x2F;imh&#x2F;python_do_notation" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;imh&#x2F;python_do_notation</a><p>[1] <a href="https:&#x2F;&#x2F;github.com&#x2F;imh&#x2F;python_do_notation&#x2F;blob&#x2F;master&#x2F;parser_example.py#L97" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;imh&#x2F;python_do_notation&#x2F;blob&#x2F;master&#x2F;parser...</a>
评论 #23342318 未加载
评论 #23339716 未加载
hydroxoniumalmost 5 years ago
Python + Functional = <a href="http:&#x2F;&#x2F;coconut-lang.org&#x2F;" rel="nofollow">http:&#x2F;&#x2F;coconut-lang.org&#x2F;</a>
评论 #23339061 未加载
评论 #23345734 未加载
评论 #23339027 未加载
评论 #23345457 未加载
评论 #23338561 未加载
federicoponzialmost 5 years ago
I like strongly typed and functional programming. But I would rather use a &quot;pythonic&quot; approach to solve problems in python. OFC there might be some cases where for example one of your dependency is python, and you still want to be able to write correct code. But in general, If you want types and functional constructs, IMO you should use something else.
throwaway_pdp09almost 5 years ago
If there was one thing I&#x27;d change with python to make it more &#x27;functional&#x27; it would be having lambdas that weren&#x27;t expression-only. I know it&#x27;s not a functional feature because it&#x27;s for stateful programming, but the lack of it disallows some nice stuff.
评论 #23338991 未加载
评论 #23340549 未加载
sobolevnalmost 5 years ago
Hi, author of `returns` here! Thanks a lot for sharing this link.<p>I would love to highlight several features of `0.14` release we are working on right now:<p>1. Typed `partial` and `curry` functions: <a href="https:&#x2F;&#x2F;returns.readthedocs.io&#x2F;en&#x2F;latest&#x2F;pages&#x2F;curry.html" rel="nofollow">https:&#x2F;&#x2F;returns.readthedocs.io&#x2F;en&#x2F;latest&#x2F;pages&#x2F;curry.html</a><p>2. `Future` and `FutureResult` containers for working with async Python! <a href="https:&#x2F;&#x2F;returns.readthedocs.io&#x2F;en&#x2F;latest&#x2F;pages&#x2F;future.html" rel="nofollow">https:&#x2F;&#x2F;returns.readthedocs.io&#x2F;en&#x2F;latest&#x2F;pages&#x2F;future.html</a><p>3. Typed functional pipelines with very good type inference: <a href="https:&#x2F;&#x2F;returns.readthedocs.io&#x2F;en&#x2F;latest&#x2F;pages&#x2F;pipeline.html" rel="nofollow">https:&#x2F;&#x2F;returns.readthedocs.io&#x2F;en&#x2F;latest&#x2F;pages&#x2F;pipeline.html</a><p>It is going to be released soon, stay tuned!
tuxxyalmost 5 years ago
The project cites this blog post[0] on the &quot;anti-pattern&quot; that is Python exceptions, and I honestly couldn&#x27;t be turned off on this project anymore after reading it if this is the inspiration behind it.<p>The examples in the README and this blog post just give me huge &quot;nope&quot; vibes. Obviously Python could learn a lot more from functional programming, but this is the wrong way to go about a lot of it.<p>0. <a href="https:&#x2F;&#x2F;sobolevn.me&#x2F;2019&#x2F;02&#x2F;python-exceptions-considered-an-antipattern" rel="nofollow">https:&#x2F;&#x2F;sobolevn.me&#x2F;2019&#x2F;02&#x2F;python-exceptions-considered-an-...</a>
评论 #23341959 未加载
BiteCode_devalmost 5 years ago
How about writting modern and proper Python first? Not to mention designing a decent API?<p>Let&#x27;s examine the README example for a minute:<p><pre><code> user: Optional[User] if user is not None: balance = user.get_balance() if balance is not None: balance_credit = balance.credit_amount() if balance_credit is not None and balance_credit &gt; 0: can_buy_stuff = True else: can_buy_stuff = False </code></pre> I don&#x27;t know if it&#x27;s been deliberatly twisted, but that&#x27;s not what I would called idiomatic or realistic for a Python program:<p>- one should probably never reach this part of the code if there is no user. But I&#x27;ll indulge the author.<p>- don&#x27;t put can_buy_stuff in an else close, what&#x27;s the point?<p>- using type hints for no reason, but not other modern facilities like the walrus operator?<p>- do we really want users without a balance? Let&#x27;s indulge this, but it seems a bad design.<p>- what&#x27;s with all those unecessary conditional blocks?<p>- credit_amount should never be None. It&#x27;s a Balance object, put a sane default value. But ok, indulging again.<p>So, you get down to:<p><pre><code> user: Optional[User] can_buy_stuff = False if user and (balance := user.get_balance()): can_buy_stuff = (balance.credit_amount() or 0) &gt; 0 </code></pre> I don&#x27;t think the solution the lib offers is superior:<p><pre><code> can_buy_stuff: Maybe[bool] = Maybe.from_value(user).map( lambda real_user: real_user.get_balance(), ).map( lambda balance: balance.credit_amount(), ).map( lambda balance_credit: balance_credit &gt; 0, ) </code></pre> And that&#x27;s if we are using the rules of the README, which are not fair.<p>If we have a well designed API, and we use a function (more testable, and hey, are we doing FP or not ?), then:<p><pre><code> def can_buy_stuff(user: User): if (balance := user.get_balance()): return balance.credit_amount() &gt; 0 return False </code></pre> Checking the user should not be part of this algo, credit_amount should be 0 if never set. We could even remove return False, I keep it because I like explicitness.<p>You could even that as a method or raise NoBalance depending of your case.<p>Bottom line, if you really feel that strongly about None, don&#x27;t jump on the bazooka to kill this fly, go to <a href="https:&#x2F;&#x2F;discuss.python.org" rel="nofollow">https:&#x2F;&#x2F;discuss.python.org</a> and advocate for PEP 505 (None-aware operators): <a href="https:&#x2F;&#x2F;www.python.org&#x2F;dev&#x2F;peps&#x2F;pep-0505&#x2F;" rel="nofollow">https:&#x2F;&#x2F;www.python.org&#x2F;dev&#x2F;peps&#x2F;pep-0505&#x2F;</a><p>It&#x27;s been deferred since 2015.<p>That doesn&#x27;t mean we should not experiment with other paradigms in Python, and I do think this lib is an interesting experiment, but I don&#x27;t find it conclusive.
评论 #23339918 未加载
karlicossalmost 5 years ago
For &#x27;Maybe&#x27; an &#x27;Result&#x27; specifically, I feel that Python builtins + mypy offer superior experience: easier, safer, and less dependencies with a similar level of verbosity.<p>For Maybe example: I think this &#x27;functional&#x27; style with fmaps in Python is problematic, because lambdas can&#x27;t be multiline. If you have sevearal lines of logic, you&#x27;d need an auxiliary helper def, and at this point it becomes as unreadable.<p>For Results: I think returning Union[Exception, Value] (where Value is the &#x27;desired&#x27; type) and then using isinstance(result, Exception) is much cleaner.<p>- it can be statically checked with mypy to ensure the same level of type safety as Rust would have<p>- minimal performance impact<p>- no extra wrapping and unwrapping in the code. You can completely ignore mypy and error handling, until you&#x27;re happy, then you harden your program by making sure it complies to mypy.<p>- no extra dependencies, third party code dealing with your library doesn&#x27;t have to deal with your wrappers! If they don&#x27;t check for error type, when Exception is encountered, the program will most likely terminate with AttributeError, which is a desirable behaviour in such situation.<p>- it&#x27;s much easier to compose: propagating error with a decorator is neat, until you have some more sophisticated logic, e.g. for error aggregation<p>- the only downside is that you end up with occasional `if isinstance(result, Exception)...`.<p>I reviewed results library specifically here [0] and elaborate on different error handling techniques in Python, including the approach I described.<p>[0] <a href="https:&#x2F;&#x2F;beepb00p.xyz&#x2F;mypy-error-handling.html#container" rel="nofollow">https:&#x2F;&#x2F;beepb00p.xyz&#x2F;mypy-error-handling.html#container</a>
评论 #23340564 未加载
cheezalmost 5 years ago
I&#x27;m a big fan of functional programming but this documentation is kind of funny, unintentionally. I realize there is no better way to do it in Python.<p>And that’s how your initial refactored code will look like:<p><pre><code> user: Optional[User] can_buy_stuff: Maybe[bool] = Maybe.from_value(user).map( # type hint is not required lambda real_user: real_user.get_balance(), ).map( lambda balance: balance.credit_amount(), ).map( lambda balance_credit: balance_credit &gt; 0, ) </code></pre> Much better, isn’t it?
评论 #23345399 未加载
ca_parodyalmost 5 years ago
Why the lambdas at all in these examples...<p><pre><code> (lambda real_user: real_user.get_balance()) </code></pre> and not<p><pre><code> User.get_balance </code></pre> (besides subclasses not getting their balance called...)
评论 #23340502 未加载
noemaalmost 5 years ago
Cool stuff but what&#x27;s with the logo? The branding is a bit too Affliction-esque for something usually associated with elegance...
FridgeSealalmost 5 years ago
Functional programming in Python:<p>Step 1: try to integrate more functional methods in your current Python programming due to their usefulness.<p>Step 2: get increasingly frustrated, and then give up, because Guido and the Python devs seemingly hate functional programming and keep hobbling it.
评论 #23345963 未加载
typenilalmost 5 years ago
The `Maybe` container seems to be a close analog of `Option` in Rust<p><a href="https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;rust-by-example&#x2F;std&#x2F;option.html" rel="nofollow">https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;rust-by-example&#x2F;std&#x2F;option.html</a>
评论 #23341478 未加载
评论 #23340254 未加载
评论 #23344946 未加载
Simulacraalmost 5 years ago
Python is all about the magic. Lambda expressions are a bit of a black box for me in Python, it would be nice if that was made more transparent, or perhaps a different function entirely
评论 #23341884 未加载
papaveralmost 5 years ago
can&#x27;t say i&#x27;m a fan of the decorator to implement functional concepts. jut feels dirty. type hints in python are just as meh. feels like it&#x27;s not taking advantage of pythons duck typing.<p>a version of try and either, with a decent do notation taking advantage of for comprehension... <a href="https:&#x2F;&#x2F;github.com&#x2F;papaver&#x2F;pyfnz" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;papaver&#x2F;pyfnz</a>
评论 #23339854 未加载
vmchalealmost 5 years ago
Why would you want to use the I&#x2F;O monad in Python?
评论 #23339852 未加载
VWWHFSfQalmost 5 years ago
this looks like it will slow down the code immensely
okasakialmost 5 years ago
&gt; But, having null checks here and there makes your code unreadable.<p><pre><code> if user is not None: balance = user.get_balance() if balance is not None: balance_credit = balance.credit_amount() if balance_credit is not None and balance_credit &gt; 0: can_buy_stuff = True else: can_buy_stuff = False </code></pre> Actually I think that&#x27;s very readable<p><pre><code> user: Optional[User] can_buy_stuff: Maybe[bool] = Maybe.from_value(user).map( # type hint is not required lambda real_user: real_user.get_balance(), ).map( lambda balance: balance.credit_amount(), ).map( lambda balance_credit: balance_credit &gt; 0, ) Much better, isn&#x27;t it? </code></pre> No?!? That&#x27;s much worse.
评论 #23345498 未加载
leshowalmost 5 years ago
writing `lambda` must get really old
评论 #23340565 未加载
blackrockalmost 5 years ago
Nice premise. But it makes the Python code look super complicated.<p>It overloads map() with a lambda function, to compose function pipelining.<p>Then, it introduces flow() as the new pipelining tool. But you have to use bind() on the last function call to return the value.<p>Interesting concepts, but unless Python incorporates this as a standard feature, then this will remain a fringe idea. And it will add significant load to the development and maintenance process of Python programs.<p>Admittedly, I like Elixir’s pipe forward concept |&gt;<p>That makes it super simple to do functional composition, and it will automatically bind and return the last value.<p>Then getting the user profile, can be like so:<p><pre><code> user_profile = userid |&gt; get_request |&gt; parse_json</code></pre>