Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Haskell language features and standard libraries in pure Python (github.com/billpmurphy)
136 points by asib on Sept 22, 2020 | hide | past | favorite | 32 comments


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.


Quite an epic effort, but (I'm guessing, due to the age of it) none of the type system stuff is checkable via mypy etc

it seems like instead there's a bunch of runtime type-checking going on (or at least... "at import time", i.e. runtime but as early as possible)


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

These folks have several excellent projects in that direction though: https://github.com/dry-python/


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.


README says Python 3.x support in the future and others have stated the library is inactive for five years .


no commits in 5 years, from reading the issues, this seems like a more maintained alternative https://github.com/evhub/coconut


While coconut looks very cool, does it include a Hindley-Milner type system and type classes?

Those are big features of Haskell that I see implemented in this repo that I couldn't see in Coconut.

But I could be mistaken. I don't know much about Coconut.


From the FAQ[1]:

> Does Coconut support static type checking?

> 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.

[1]: https://coconut.readthedocs.io/en/master/FAQ.html#does-cocon...

[2]: https://github.com/python/mypy/blob/master/mypy/typeanal.py


this fork has a working py3 version https://github.com/mvaled/hask



Applicative : minimally complete definition: pure

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.


Really impressive to pull this off!

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.

type Either<E, A> = Left<E> | Right<A>


This is also a nice recent attempt on utilizing Python ecosystem and FP features of Haskell(Purescript):https://github.com/purescript-python/purescript-python/blob/...


Sadly, creating decent-looking multi-line lambda functions is not really possible in Python, afaik.


Why does it need to be anonymous if it's multi line? You can just do a local 'def'.


You cannot use def within function call parenthesis.


But you can pass a def'd function within function call parentheses.


I would still prefer having a multiline lambda. We have this:

    def f(x):
      y = foo(x)
      z = bar(y)
      // ...
      return x
    some_obj.do_later(t, f, a, b, c)
I would prefer:

    some_obj.do_later(t, lambda x: {
      y = foo(x)
      z = bar(y)
      // ...
      return x
    }, a, b, c)
Maybe ( instead of {? I'm not sure that's possible to parse. Regardless, something like this would be good.


Yes, I have wanted that before, and it could use existing valid syntax:

    some_obj.do_later(t, (lambda x:
        # (presently only a single non-comment line would be valid)
        x
    ), a, b, c)


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)
  )

from `https://news.ycombinator.com/item?id=23346534`


I suppose lambdas are already a bit weird for ending with a : without starting a new code block.

Good luck fixing that though.


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.


Lazy evaluation lists is nice.

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, ...])`

I wonder how ubiquitous lazy evaluation is?


Simon Peyton Jones said that lazy evaluation was a mistake.


> 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.

https://www.microsoft.com/en-us/research/podcast/functional-...


When did he say that?

From what I have read he has stated that it forced purity and I’d be interested to see the context where he calls it a “mistake”.


Glad to hear he said that. He is right.


Can you elaborate on your thoughts?




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: