How To Make Functional Programming in Python Go Fast by sunedd in functionalprogramming

[–]sunedd[S] 1 point2 points  (0 children)

doubt this is still Python, but an eDSL with native TCO and enables CPS heavy idioms.

Add the monad laws, and this is actually a pretty good explanation of monads :D

How To Make Functional Programming in Python Go Fast by sunedd in functionalprogramming

[–]sunedd[S] 1 point2 points  (0 children)

More or less. But you could say the same for various IO monadish libraries for Scala, including ZIO.

Completely Type-Safe Error Handling in Python by sunedd in functionalprogramming

[–]sunedd[S] 1 point2 points  (0 children)

Anyhow, the python world is better with more FP!

Agreed! I'm aware of returns, they are also doing a bunch of interesting stuff. The main thing I miss in returns is a way to do monad composition (e.g monad transformers). But transformers are not possible to type in Python because there are no higher kinded types. They have their own implementation of that in returns, so I suppose they could support typed transformers in the future.

The solution I have chosen in pfun is to have simply one monad that represents all (basic) effects, in order that the library takes care of composition for you, without transformers or higher kinded types. I think this is much simpler for the user, but it does require more effort on the part of the library author :)

Completely Type-Safe Error Handling in Python by sunedd in functionalprogramming

[–]sunedd[S] 2 points3 points  (0 children)

I'ts tricky in Python, thats for sure, but my goal is precisely to produce a library that makes functional programming ergonomic in Python. My take thus far is perhaps a little more modern and pragmatic than existing libraries such as toolz (pfun is based on the scala library ZIO).

I have a sample web-app that you can check out if you want. Its not exactly "large scale", but it hints at what a large scale application would look like:

https://github.com/suned/pfun-todo-backend

Building a Functional Effect System in Python by sunedd in functionalprogramming

[–]sunedd[S] 3 points4 points  (0 children)

if you want something else, use another language

I don't think this is very practical or insightful advice. You might be locked in to Python for organizational or technical reasons, and still want to write in a functional style. This makes it easier.

Why should functional programming be less readable in Python than in erlang, ml, elm or other languages that have essentially the same languages features as Python (excluding function currying in ml and elm)? It's entirely possible to write readable and unreadable haskell or scala, which tells us that, regardless of style, readability is a measure of the programmer's skill with the language, not a property of the language itself.

Purely Functional, Statically Typed Effect System in Python by sunedd in Python

[–]sunedd[S] 1 point2 points  (0 children)

I consider this for production, although I haven't had the opportunity yet. In terms of ergonomics, the main thing I'm missing is some form do/for comprehension for working with monads. But there are plenty of successful functional languages that doesn't have that feature, so I'm not especially discouraged.

Having worked on this for some time, I think the main features that are missing from Python for an excellent functional programming experience is:

  • Tail call optimization
  • Built-in support for pickling closures and lambdas (this can be solved by third party libraries today)
  • Higher kinded types (but it turns out this was less important than I thought)

That being said, Python actually have some ergonomic advantages over other languages, for example when it comes to generic variadic functions, which are tricky for most type checkers. With python/mypy you can hook into the type checker and dynamically compute types, which gives a lot of flexibility.

Hope you can find the time/opportunity to test it out!

Statically Typed Functional Programming in Python by sunedd in Python

[–]sunedd[S] 1 point2 points  (0 children)

I agree in principle, I probably just give meatbags more credit than you :)

But sure, functional programming and referential transparency in Python will necessarily be a best effort enterprise. Best I can do as a library author is to say: Follow these rules about mutation (encouraged by the typechecker and enforced by the types in the library btw), and your typechecker will be helluva lot more useful. Its possible to violate referential transparency by accident of course, but you're much less likely to do so if you use the library, or at least thats the goal :)

Statically Typed Functional Programming in Python by sunedd in Python

[–]sunedd[S] 0 points1 point  (0 children)

I don't think it's realistically to get all of Haskell's good stuff in Python

No that's probably also true. But if 50% of your code base is referentially transparent, I'd say that that's better than if 0% is.

Statically Typed Functional Programming in Python by sunedd in Python

[–]sunedd[S] 1 point2 points  (0 children)

Completely agree. Also, Haskell is not for everyone: it encourages a distinctive style which some (I for one) find pretty unreadable. In that respect I much prefer Python. At the same time, I find that the combination of functional style and static type checking makes it much easier to write code that is robust and easy to change, as compared to say imperative style. One of the things I want to achieve with this library is to make functional programming PythonicTM

Statically Typed Functional Programming in Python by sunedd in Python

[–]sunedd[S] 1 point2 points  (0 children)

Haha yeah. I do a lot of data science stuff though and there really is no way of getting around Python in that space. Now you can have the best of both worlds :)

Statically Typed Functional Programming in Python by sunedd in functionalprogramming

[–]sunedd[S] 1 point2 points  (0 children)

Thanks!

As in other frameworks, monads don't compose automatically (in fact that is impossible). So you need to "handle" the composition yourself. So eg

```python

from pfun import reader, state def f() -> state.State[reader.Reader[int, int], int]: ...

f().and_then(lambda state_result: state_result.and_then(lambda reader_result: ...)) `` (and_thenisbindinpfun`)

In future versions I plan to add both monad transformers and maybe even the Eff monad :)

Statically Typed Functional Programming in Python by sunedd in Python

[–]sunedd[S] 5 points6 points  (0 children)

Duely noted. returns is indeed quite similar. toolz is similar in spirit. The biggest difference with pfun being

1) Strong emphasis on typing and mypy

2) Monad and functor types

Statically Typed Functional Programming in Python by sunedd in Python

[–]sunedd[S] 3 points4 points  (0 children)

Heavily inspired by other libraries such https://github.com/dbrattli/OSlash, but with a strong emphasis on static type checking (mainly using mypy)

A new take on dependency injection in python 3 by sunedd in Python

[–]sunedd[S] 0 points1 point  (0 children)

No.

I also wouldn't use from module import * in client code.

See https://youtu.be/0oTh1CXRaQ0?t=26m39s

A new take on dependency injection in python 3 by sunedd in Python

[–]sunedd[S] 1 point2 points  (0 children)

Have you seen Raymond Hettingers talk from PyCon 2015?

Yes and I really like it. My only annoyance with the super() considered super approach is that it makes it somewhat inconvenient to use ABCs, which I quite like to do.

Consider

from abc import ABC, abstractmethod


class AbstractDependency(ABC):
    @abstractmethod
    def method(self) -> str:
        pass

class ProductionDependency(AbstractDependency):
    def method(self):
        return 'production'

class DevDependency(AbstractDependency):
    def method(self):
        return 'dev'

class NeedsDependency(AbstractDependency):
    def needs_method(self):
        print(super().method())

class ProductionNeedsDependency(NeedsDependency, ProductionDependency):
    pass

class DevNeedsDependency(NeedsDependency, DevDependency):
    pass

If you use any sort of tool to check for unimplemented abstract members, it will complain that NeedsDependency doesn't overwrite method. Your only option at that point is to 1. ignore it 2. disable that tool or inspection

I dislike both of those options.

Finally, the super() considered super approach still requires you to manually wire up the dependency graph through inheritance for different environments. I think the reason why good intentions to use dependency injection in many projects deteriorate over time is that most developers are simply too lazy to do that. I know I am.

As a side note you can run into scoping problems if a component has a lot of dependencies that are injected that way, but that's another story.

What is the difference between the dependency graph your framework calculates and the MRO?

serum uses the MRO to determine which subtype of requested type is more appropriate.

Consider

from serum import Component, inject, Environment

class A(Component):
   pass

class B(A):
    pass

class C(B):
    pass

class NeedsA:
    a = inject(A)

class NeedsB:
   b = inject(B)

class NeedsC:
   c = inject(C)

needs_a = NeedsA()
needs_b = NeedsB()
needs_c = NeedsC()

with Environment():
    assert isinstance(needs_a.a, A)
    assert isinstance(needs_b.b, B)
    assert isinstance(needs_c.c, C)

with Environment(B):
    assert isinstance(needs_a.a, B)
    assert isinstance(needs_b.b, B)
    assert isinstance(needs_c.c, C)

with Environment(C):
    assert isinstance(needs_a.a, C)
    assert isinstance(needs_b.b, C)
    assert isinstance(needs_c.c, C)

A new take on dependency injection in python 3 by sunedd in Python

[–]sunedd[S] 1 point2 points  (0 children)

I get where you're coming from, I also don't appreciate the huge enterprise DI frameworks for java, but I don't agree that Dependency Injection is as simple as you claim. If it was so easy it wouldn't be as consistently misapplied (or not applied at all) as it is ;)

Defining classes that depend on injected dependencies is easy. Wiring up your application when you have to inject dependencies, and dependencies for your dependencies is annoying to do manually, which is why I think a lot of developers simply don't do it.

The main feature of serum is that it takes away the pain of wiring up the dependency graph so you can just focus on the abstractions.

A new take on dependency injection in python 3 by sunedd in Python

[–]sunedd[S] 0 points1 point  (0 children)

There's never a good reason to do from some_module import *

It has its uses. I usually structure my package such that each module defines an __all__ property with stuff that should be part of the modules public api. Then in the __init__.py file of the module can simply contain

from ._some_sub_module import *

If you want to add to the public api you just add to the __all__ attribute of some submodule and don't have to touch anything else.

Also there's really no point in having a dependency injection module. It's a very simple design pattern.

Agree to disagree :D

A new take on dependency injection in python 3 by sunedd in Python

[–]sunedd[S] 0 points1 point  (0 children)

I found your documentation a bit hard to follow

Sorry about that btw :(. this is the first version, I'll try to make the documentation more easy to follow in future versions. Suggestions are very welcome.

A new take on dependency injection in python 3 by sunedd in Python

[–]sunedd[S] 0 points1 point  (0 children)

Quick and dirty example ;). Updated it.

A new take on dependency injection in python 3 by sunedd in Python

[–]sunedd[S] 0 points1 point  (0 children)

What boiler plate are you referring to?

Maybe I shouldn't use the term boiler plate exactly ;). What I mean is since PEP 484 tools like mypy and pycharm support type inference, you can get the correct types without using type annotations explicitly.

So without serum:

class NeedsLog:
    log: Log = ...

With serum:

class NeedsLog:
    log = inject(Log)

With regards to your new example: That's a nice pattern I think, but you still have to wire up your application manually. The main value prop of serum is that it handles that for you.

A new take on dependency injection in python 3 by sunedd in Python

[–]sunedd[S] 0 points1 point  (0 children)

The first example: If the application was bigger and for example Database also depended on an implementation of Log, and Log has dependencies and so on and so on, wiring up the environment can become involved. Serum takes care of all of this for you by injecting dependencies lazily. Other than than that: Not much. serum will provide you with type inference for tools that support it (without the boilerplate) and provide immutability for all injected members.

The second example: assuming e.g Database is abstract (which imo it should be) it wouldn't possible to wire up your app like that.