📜 ⬆️ ⬇️

Snake and coconut

I love Python. No, really, this is an excellent language, suitable for a wide range of tasks: here you will be working with the operating system, web frameworks for every taste, and libraries for scientific computing and data analysis. But besides Python, I like functional programming. And the python in this regard is not bad: there are closures, anonymous functions and in general, the functions here are first class objects. It would seem, what more could you ask for? And here I accidentally stumbled upon Coconut - a functional language compiled in Python. All fans of Python and OP I ask under the cat.


What? Functional language compiled in Python? But why, after all, functional features and so full, but if you want additional perversions , that is, the module toolz.functoolz? But let's consider a simple task: we need to add the squares of the numbers from a certain list.


l = [1, 2, 3, 4, 5] 

Possible solutions


Imperative decision "in the forehead":


 def sum_imp(lst): s = 0 for n in lst: s += n**2 return s 

Using map and reduce (looks creepy):


 from functools import reduce from operator import add def sum_map_reduce(lst): return reduce(add, map(lambda n: n**2, lst)) 

Using list generators (pythonic-way):


 def sum_list_comp(lst): return sum([n**2 for n in lst]) 

The last option is not so bad. But in such cases you want to write something in the spirit


 sum_sqr(lst) = lst |> map(n -> n**2) |> sum 

Yes, just like in OCaml, only without strict typing (we have a dynamic language). And what if I tell you that with Coconut we can really do that? Use it to write


 sum_sqr(lst) = lst |> map$(n -> n**2) |> sum 

and get a complete solution to the task without function calls (from_functions (from_functions))).


Features


The authors of the language write that it adds the following features to Python:



It is also worth noting that the language can work in the interpreter mode, compiled into Python source codes and used as a core for Jupyter Notebook (I haven’t checked it myself yet, but the developers write what they can).


And now we’ll dwell on some possibilities in more detail. All examples were tested on Coconut 1.2.1.


Lambda expression syntax


I’m sure that it’s not the pain of lambda expressions in python that pains me. I even think that she was specially created to be used as little as possible. Coconut makes the definition of an anonymous function exactly as I would like it to be:


 (x -> x*2)(a) #  ,  (lambda x: x*2)(a) 

Composition of functions


The composition of functions here looks almost like in Haskel:


 (f .. g .. h)(x) #  ,   f(g(h(x))) 

Partial application


The functools module has a partial function that allows you to create functions with fixed arguments. It has a significant drawback: positional arguments must be substituted strictly in order. For example, we need a function that raises numbers to the fifth power. Logically, we should use partial (we just want to take a function and fix one of the arguments!), But this will not give any gain (pow in both cases is used to distract from the fact that it is an embedded operation):


 from functools import partial from operator import pow def partial5(lst): return map(lambda x: partial(pow(x, 5)), lst) #  ! def lambda5(lst): return map(lambda x: pow(x, 5), lst) #    

What can Coconut have to offer? Here's what:


 def coco5(lst) = map$(pow$(?, 5), lst) 

The $ symbol immediately after the function name indicates its partial use, eh? used as a placeholder.


Pipelines


Another simple concept that is often used in functional languages ​​and even in the well-known bash. In total there are 4 types of pipelines:


PipelineTitleUsage exampleExplanation
|>simple straightx |> ff (x)
<|simple reversef <| xf (x)
| *>multiargument straightx | *> ff (* x)
<* |multiargument reversef <* | xf (* x)

Pattern Matching and Algebraic Types


In the simplest case, the pattern matching looks like this:


 match '' in '' if ' ': '' else: '' 

Guard and block else may be missing. In this form, pattern matching is not very interesting, so consider an example from the documentation:


 data Empty() data Leaf(n) data Node(l, r) Tree = (Empty, Leaf, Node) def depth(Tree()) = 0 @addpattern(depth) def depth(Tree(n)) = 1 @addpattern(depth) def depth(Tree(l, r)) = 1 + max([depth(l), depth(r)]) 

As you might guess, Tree is a type-sum that includes different types of nodes in a binary tree, and the depth function is intended for recursively calculating the depth of a tree. The addpattern decorator allows you to dispatch using a template.
For cases when the result should be calculated depending on the first suitable template, the keyword case is entered. Here is an example of its use:


 def classify_sequence(value): ''' ''' out = "" case value: match (): out += "" match (_,): out += "" match (x,x): out += " "+str(x) match (_,_): out += "" match _ is (tuple, list): out += "" else: raise TypeError() return out 

Parallel execution


Coconut's parallel_map and concurrent_map are just wrappers over ProcessPoolExecutor and ThreadPoolExecutor from concurrent.futures. Despite their simplicity, they provide a simplified interface for multiprocess / multithreaded execution:


 parallel_map(pow$(2), range(100)) |> list |> print concurrent_map(get_data_for_user, all_users) |> list |> print 

Conclusion


I have always been jealous that in .Net there is F #, under JVM - Scala, Clojure, about the number of functional languages ​​compiled into JS, I’m generally silent. I finally found something similar for Python. I’m almost sure that Coconut will not get wide distribution, even though I would like to. After all, functional programming allows you to solve many problems concisely and elegantly. Often, even without losing the readability of the code.


Language site


')

Source: https://habr.com/ru/post/322000/


All Articles