I posted this because, frankly, I was pretty amazed that someone managed to reproduce these features in Python and lose almost none of the ergonomics of Haskell. So from a purely academic perspective, I think this is a very impressive feat.
Having said that, whenever I consider using something like this - language features of language A ported to language B - I always conclude that it doesn't make sense. If I want those features, I might as well just use language A. Trying to shoehorn them into language B is just going to make it difficult for newcomers to the codebase. That's not even mentioning the fact that these libraries inevitably have "blind spots" in terms of what's been (re)implemented. I'll probably realise hours or days in that that one language feature I need to implement something doesn't work correctly and now I've got to write some ugly workaround (which defeats the point of using the library for cleaner code), or scrap the work I've done and return to using vanilla language B.
One reason might be to leverage the Python package ecosystem while not missing some features of Haskell that you might like. Though, on the whole completely agree.
Indeed, I guess much of the type annotation stuff would be much easier with type hints from Python 3.6+ (https://docs.python.org/3/library/typing.html), plus it might add some level of compatibility with recently developed static analysis tools like mypy, pyright, pyre.
I have seen various efforts to do this stuff in a way that is checkable via mypy (i.e. using Python's own type system + as much dynamism is still type-able) and so far it looks like it's a much harder task
That's quite interesting. I guess one could try to do something even cleaner than this https://github.com/dry-python/classes using type hints only and code transformation based on Python ASTs (see e.g. https://github.com/berkerpeksag/astor). I have done something similar for (typed) Python-to-C transpilation for fun (https://github.com/zanellia/prometeo), but, now that I think about it, it could be used to implement typed polymorphism for Python classes quite easily.
> Yes! Coconut compiles the newest, fanciest type annotation syntax into version-independent type comments which can then by checked using Coconut’s built-in MyPy Integration.
So it uses MyPy. I've never seen documentation on what overall algorithm they use, and the code[2] is not an easy read.
Huh? Where's (<*>) or liftA2? It's nice having all those types and everything to work over but if the applicative instance is wrong then the monad instance is wrong and then there isn't really a point in using the library? The nice thing about haskell is that all of the laws can be covered by quickcheck. Would be cool if there was something similar here!
Aha yes interesting. I would say that I think this is a minor issue in the grand scheme. The meat of this library is, to my eyes, the type system and language features. More concretely, if the implementation of typeclasses is correct, I'm less concerned that the definition of Applicative is not (although I recognise that it doesn't necessarily inspire confidence). Fixing that definition is relatively straightforward.
Yeah I get that, but then again the Semigroup, Monoid, Functor, Applicative and Monad classes should aim to be correct because they form the base of a lot of other typeclasss. Maybe this project is something that I can contribute to in my free time :). I was missing a lot of the functional language features in python. It's a shame that it's still so clunky to work with lambdas etc.
I think it's great to see more fp inspired libraries popping up in a lot of places, especially for languages that are "known to ship" and where you can apply fp programming patterns in an incremental style instead of going "all in" with a pure fp language.
The more I'm exposed to fp concepts, the more I think we have a lot to win with exposing more and potential alien programmers to the subject to pick up the good parts.
I can recommend fp-ts in case you're doing web stuff, their either implementation looks nicer and it's in active support.
In Python people are encouraged to follow styles for code as a communication tool between developers. If you just really want your code to "look nice" you can have things like this:
def begin(*args):
return args[-1]
begin(
func := lambda x, y: begin(
z := int(input()),
x + y + z
),
func(1, 2)
)
Of course you can. But it's very different. A lambda is guaranteed to only be used by the function it's passed to. A local def pollutes the scope with an additional identifier that leads to less code clarity.
Strongly typed and purely functional are very appealing, but lazy evaluation is what really differentiates Haskell in my opinion. `take 5 (repeat 0) —- [0,0,0,0,0]` and equivalent in hask `take(5, L[0, 0, ...])`
> Host: How did laziness and purity come together?
Simon Peyton Jones: So, Haskell’s initial defining characteristic was that it was a lazy language. That’s what brought that particular group of people together, what we thought was exciting and cool. But in retrospect, I now think what was much more important was that laziness forced Haskell to be a pure language. By which I mean, in a call-by value functional language like ML or Lisp, if you wanted to print something it was too tempting to have a function, in quotes, which, when you call it, would print something as a side effect. That is, it wouldn’t just return well what would print return? Unit or 3 or something. But it would print something on the side. So, we couldn’t do that in a lazy language because we couldn’t predict the evaluation order well enough. So, laziness kept us pure. And purity was embarrassing for a long time, because you couldn’t really do much by way of input/output. You couldn’t print things or open files or launch missiles or sail the boat. So that forced us to invent what came to be called monadic input/output. And there was another classic example which Phil Wadler, my colleague at Glasgow, took ideas from the logic world. The theory of monads developed by various people. But he was particularly drawn on the work of Eugenio Moggi, who was very much a theorist. Phil Wadler wrote this wonderful paper comprehending monads in which he described monads as a programming idiom. And then he and I subsequently wrote a paper called ‘Imperative Functional Programming’ which showed how you can apply monadic programming to do input/output to affect the world. And that idea has been wildly infectious. That’s spread to all sorts of places. So, people now use the monadic thought pattern as a design idea for designing their programming languages or ways to… you could see it all over the place now. But it only happened because we were stuck with purity because we had laziness. It was another place where the sort of theory both helped the practice and also almost forced the practice, because we would have had to break with our principles too much to just have side effects. So, we were stuck with no side effects and were forced to invent this alternative way of going about things.
Having said that, whenever I consider using something like this - language features of language A ported to language B - I always conclude that it doesn't make sense. If I want those features, I might as well just use language A. Trying to shoehorn them into language B is just going to make it difficult for newcomers to the codebase. That's not even mentioning the fact that these libraries inevitably have "blind spots" in terms of what's been (re)implemented. I'll probably realise hours or days in that that one language feature I need to implement something doesn't work correctly and now I've got to write some ugly workaround (which defeats the point of using the library for cleaner code), or scrap the work I've done and return to using vanilla language B.