
Coconut: Pythonic functional programming - andybak
http://coconut-lang.org/
======
weberc2
This seems like a neat project but I can’t say I ever wanted Python to be an
even bigger language... Ideally we would have a Python-like that eschews
unnecessary features like inheritance and much of the magic that makes Python
hard to optimize (and often hard to understand), and with a type system (even
an optional type system) that is better than Mypy.

I’m not 100% sure what that would look like, but I would ditch classes (and
thus inheritance) for named tuples, make most things immutable by default,
include enums and pattern matching (that the type system would check; I hardly
see the point in dynamic pattern matching). If possible, typed code would
compile to C extensions or similar. Oh, and exceptions would go away in favor
of a Rust-like Result type.

~~~
elcomet
You should check nim out, it's a python-like language that compiles to C.

~~~
azhenley
I also recommend looking at Nim. It has Python-like syntax but it feels very
different than Python for me when using it. Stellar language though that has
been getting a lot of attention!

~~~
weberc2
Thanks for the recommendations, folks. I'll take a look!

------
lenticular
This is pretty cool. I'm not a huge Python fan, but I wind up using it quite a
bit for ML tasks. Functional programming in Python is essentially impossible,
between nearly everything being mutable and the terrible one-line lambdas. I
know Python is all about "there should be only one way to do it," but that
typically doesn't map (ahaha) at all to how I think.

~~~
enedil
You say "ML" tasks. Do you mean StandardML or Ocaml?

~~~
alangpierce
My reading was "machine learning".

------
diarmuidc
Looking at the example code, it seems that this is perl-ifying Python. And I'm
not saying that as a good thing. The code is more terse and less readable &
understandable.

~~~
marcosdumay
It's haskellfying it.

Some of those are very needed constructions (like algebraic data types with
pattern matching), but it's adding an entire sub-language into a language that
is built on the goal of being simple. I'm not sold into it either.

~~~
cbdumas
I could be missing something but saying this language has ADTs is stretching
the definition of ADT a bit much for me. ADTs are defined by combining simpler
types (usually with sum and product types) but that does not seem to be
possible in Coconut.

~~~
haskellandchill
Very disappointing, like why bother doing ADTs if you aren't going to do them
right and have exhaustive pattern matching.

------
akhong
I recently gave a talk on Coconut in PyCon Bangkok:
[https://youtu.be/24DWw6Ozkvo](https://youtu.be/24DWw6Ozkvo)

~~~
eindiran
I really enjoyed your talk. Thank you for giving the talk and sharing the
link!

------
hmaarrfk
> And Coconut code runs the same on any Python version, making the Python 2/3
> split a thing of the past.

My understand was that the big issue was the fact that [third party] libraries
assume that strings were made of 8bits characters.

How does coconut solve that issue?

Seems a little misleading....

if you import enough things from `six` or `__future__` then you code will run
the same on both python 2/3.

some things like fancy tuple expansion aren't available if you work with that
subset, but yeah, most things are OK.

~~~
JoBrad
I haven't used Coconut beyond some dabbling last time it made HN's frontpage,
so someone with more experience may be able to provide a better answer.
However, the syntax is based on Python 3, and they use their own builtins for
both Python 2 and 3 to maintain compatibility. Some functionality can't be
back-ported to Python 2 (tuple unpacking with *, f strings, etc.), and there
is more info about that at the link below.

[https://coconut.readthedocs.io/en/master/DOCS.html#compatibl...](https://coconut.readthedocs.io/en/master/DOCS.html#compatible-
python-versions)

~~~
hmaarrfk
Thanks for the link.

I wonder how they are doing tail call optimization in python

~~~
eindiran
Here is where TCO is implemented in the Coconut compiler code:

[https://github.com/evhub/coconut/blob/07e311fb8f69861d30e58f...](https://github.com/evhub/coconut/blob/07e311fb8f69861d30e58f0de7861f2ef7351503/coconut/compiler/compiler.py#L1611)

~~~
zbentley
That's clever and horrifying. Clever because writing a regex-based
preprocessor for a complex, dynamic language that adds TCO and actually
_works_ in most cases is impressive. Horrifying because . . . it's a regex
based preprocessor that rearranges arbitrary function code in a complex,
dynamic language.

------
darkpuma
"Pythonic functional" seems like a contradiction of terms, considering
python's infamous hostility (e.g. [http://fold.sigusr2.net/2010/03/guido-on-
functional.html](http://fold.sigusr2.net/2010/03/guido-on-functional.html)) to
functional programming seems like a key part of what it means to be pythonic.

That said, it looks a lot more pleasant than Python. The addition of pattern
matching alone makes this seem like a very worthwhile project, a big
improvement on Python.

~~~
sgillen
I’m not sure what you mean, what about python is notoriously unfunctional?

~~~
darkpuma
It's _capable_ of functional programming in the sense that functions are first
class values that you can pass around, but it is infamously hostile to
functional programming. For example, python _still_ doesn't have multi-line
lambdas, and the justifications for why always boil down to it being
"unpythonic".

Furthermore over the years Guido has made it pretty clear that he doesn't
particularly like or care about functional programming: [https://python-
history.blogspot.com/2009/04/origins-of-pytho...](https://python-
history.blogspot.com/2009/04/origins-of-pythons-functional-features.html)

~~~
pseudalopex
Requiring complex functions to have names isn't hostile to functional
programming.

~~~
darkpuma
It really is though. It doesn't prevent it, but it sure as shit doesn't
encourage it.

~~~
pseudalopex
It subtly discourages functional programming when a for loop would be faster
and more readable.

~~~
fulafel
Python really took the direction of preferring list/generator comprehensions
for this kind of thing, encouraging their use over both imperative loops and
basic HOFs like map/filter. List comprehensions are declarative and hence
functional constructs.

Generators also get you another FP checkbox because you now have laziness in a
very accessible form. You get building blocks like infinite sequences and so
on. And you have access to all the normal primitives like reduce, take,
partial, groupby etc in the itertools/functools std modules.

------
40acres
I like the idea but am not fond of the execution, particularly around the
aesthetics.

One of the reasons I love Python is because of it's syntactic brevity and
conciseness, once you get to intermediate python there are some weird forms of
syntactic sugar (magic functions and unpacking for instance) but visually the
language has less clutter than most popular languages. Coconut really just
seems to remove that aspect.

------
CodeSheikh
Is it just me who finds adjective "Pythonic" usage unnecessary and somewhat
elitist? Let's be honest, there are no other language counterparts (Java as
Javish?! or JS as JSish?!) for such adjective and "Pythonic" seems to be used
by a sub-set of Python community. Basically it is idiomatic.

~~~
traverseda
I think that "pythonic" does mean something, and that when they say "pythonic"
they are actually trying to communicate something.

JS and Java... well they're not something I think a lot of programmers want to
be. JS has a pretty complicated ecosystem that a lot of developers don't like.
Java is good at what it's good at, but it's not very fun.

What I see a lot of is "lisp" or "lisp-like" and "pythonic". Those languages
are notable for being considered fun by a lot of programmers.

But yes, it's idiomatic. Python is an idiomatic programming language that has
sacrificed a lot for that ideology. Now that guido is gone it's less
ideological, and we're getting things like type-hinting.

When people try to apply that same ideology to other fields, sometimes they
call it pythonic. When they try to apply the lisp ideology to other fields,
they just call it a lisp dialect instead of lisp-ish.

~~~
miohtama
Guido was working on Dropbox with Python. One of areas was type hinting (of
large Dropbox Python codebase), so it is partially coming from him.

Learnt this in Pycon 2014 if I recall correctly.

~~~
bakery2k
That's right - Guido has been very much in favour of adding type hints to
Python.

Are type hints Pythonic? I personally don't think so - to me, they don't match
the philosophy of the rest of the language. On the other hand, one could argue
that the definition of Pythonic is simply "whatever Guido likes".

------
rthy
Alternatively, the toolz package (
[https://toolz.readthedocs.io/en/latest/](https://toolz.readthedocs.io/en/latest/)
) is a nice way of getting some additional functional programming capabilities
while using the standard CPython interpreter.

------
vram22
There's also Hy:

[http://docs.hylang.org/en/stable/](http://docs.hylang.org/en/stable/)

"hy - A dialect of Lisp that's embedded in Python"

------
frutiger
Nice effort and I really like the premise.

I hate to be negative and I appreciate this may be due to the requirement to
make Coconut a superset of Python, but the pattern matching and the partial
application look anything but elegant (or Pythonic) to me.

------
Majestic121
I'm a huge fan of the lambda syntax :

x -> x * 2

It looks much cleaner than the traditional :

lambda x : x * 2

Would a PEP adding this syntax have any chance to pass ?

~~~
runarberg
Just came back to python after several years in javascript. I've found that
the functions you need are often already provided in the standard library (for
example the `operator` module[1]).

So where in javascript you would write:

    
    
        const double = x => x * 2
    

In python you can simply write:

    
    
        from operator import mul
        double = mul(2)
    

[1]:
[https://docs.python.org/2/library/operator.html](https://docs.python.org/2/library/operator.html)

~~~
bakery2k
The Python equivalent of your JavaScript example is simply:

    
    
        def double(x): return x * 2
    

Python's `lambda` construct creates anonymous functions - its limitations mean
it should only be used when anonymity is required. If a function is to be
given a name, there is no reason to use a lambda over standard function
syntax.

------
dang
Discussed in 2016:
[https://news.ycombinator.com/item?id=11960692](https://news.ycombinator.com/item?id=11960692)

------
otikik
I instinctively distrust every project that self-describes as "elegant".
Doubly so if it also says it is "simple".

You docs should _show_ it, not _tell_ it.

~~~
arcosdev
I get the nausea shivers when something is described as "curated"

------
vages
The pipe operator alone makes this worth using.

~~~
aloisdg
Are you familiar with F#?

~~~
busterarm
Or Elixir.

------
iamapipebomb
I think I could replace bash with xonsh[0] as my default shell if coconut's
pipe syntax were available!

[0] [https://xon.sh/](https://xon.sh/) [1]
[https://github.com/xonsh/xonsh/issues/1336](https://github.com/xonsh/xonsh/issues/1336)

------
jhuni
The first question that comes to mind is, what is wrong with using the JVM or
the CLR as a compilation target for such a language. The only thing that I can
think of is that they want to exist on the Python platform, which makes some
sense. Python is taking over the computing industry and programming education
and it does have a lot of libraries. Perhaps Python should have a standard
Python virtual machine, but that almost certainly is never going to happen,
for multiple reasons. So here you are stuck with a transpiler. A transpiler
whose purpose is to make a functional language compile to a language which was
explicitly designed not to be functional at all.

~~~
zmmmmm
Yes. It is a bit of a head scratcher why people would be going to enormous
effort to transpile to an execution environment that is as gimped as Python's.
I use Groovy pretty much as "python for the JVM", and a big reason for that is
simply that Python's runtime limitations are unacceptable to me from a basic
engineering standpoint (primarily, GIL). I guess Python's ecosystem is big
enough now that the selling point of "you can use all your favorite libraries"
is enough of a drawcard?

------
technicalbard
I still don't understand why Common Lisp isn't more popular

------
udfalkso
I'm seeing a lot of the things I like about Elixir here. Very slick.

Are there performance implications?

~~~
eindiran
There are two things you can do to ensure that the transpiled Python is as
fast as possible. First, disable TCO (while leaving TRE enabled) with the
`--no-tco` argument to the compiler. Second, make sure you set the target
version of Python correctly. This will allow the compiler to make a number of
optimizations that are specific to different Python versions.

Overall, for the majority of use cases I have found Coconut code to be
approximately as performant as Python code written by hand. The compiler speed
can leave a little to be desired though.

------
wiradikusuma
So it's like CoffeeScript
([https://coffeescript.org/](https://coffeescript.org/)) to JavaScript?

~~~
purrpit
Except not all of JavaScript is a valid CoffeeScript.

------
portal_narlish
How are the "algebraic data types" algebraic if they don't express any
relation to each other?

This seems like a cool syntactic layer for people that are already writing
Python and wishing for a more functional style. However to call this a
functional language would betray the definition.

------
Insanity
I really like the look of this. Most programming in my spare time is done
within a more functional paradigm.

But I can't help but wonder if companies ever go for these kind if extensions
/ frameworks / languages.

I will play around with this one though!

------
ivoras
Heh... "compiles to Python code" \- so still no efficient multithreading :(

------
agumonkey
related, hy-lang (clojury python transpiler)

------
snthpy
> The difference between | _> and |> is exactly analogous to the difference
> between f(args) and f(_args).

Should the order of the second list be reversed?

i.e. |> corresponds to f(args) and | _> corresponds to f(_args)

------
foobar_
How is this implemented ?

~~~
eindiran
The code is available on Github:
[https://github.com/evhub/coconut](https://github.com/evhub/coconut)

------
caymanjim
I wish people would stop using |> as an operator. It's exceedingly awkward to
type, and I shouldn't have to rely on editor tricks to input code.

------
Walkman
Coconut, aka take a beautiful language and fuck it up with ugly syntax :D Well
done!

------
bredren
I really enjoy coconuts and food products derived from coconuts, so the name
is absolutely terrific as far as I'm concerned.

