"FP in Python with Coconut!" |> print

This post introduces the Coconut language, a functional superset of the Python language, which aims to create elegant, functional code while remaining in a familiar Python environment and libraries, and provides some illustrative examples.





", !" |> x -> x.replace('', 'Coconut') |> print
      
      



The Coconut language (at the time of this writing, its latest version is v1.5.0) is a function-oriented strict superset of the Python language, and therefore everything that is valid for Python is also valid for Coconut, while Coconut is transpiled to Python. In fact, Coconut is a playground for mastering the paradigm of functional programming, testing ideas in the field of FP, practicing techniques for solving problems in this paradigm and for educational purposes.





The language website page states that Coconut is designed to be useful to you. Coconut expands the Python programmer's repertoire by leveraging the tools of modern functional programming, making these tools easier to use and more powerful. In other words, Coconut does with functional programming what Python did with imperative programming.





Hopefully this post proves these claims in practice.





Just in case, you can install Coconut using the pip package manager: pip install coconut







Coconut is a strict superset of the Python language

Writing Python code in a functional style can be tricky, ranging from minor inconveniences, such as verbose lambda syntax, to more serious problems, such as chaining lazily computed iterators and pattern matching. Coconut is a functional superset of the Python language that aims to create elegant and functionally oriented Python-style code.





, Python . Python -, , . , . , .





2016 Python , - , Haskell Scala. Coconut , Python. , . , print(", !")



", !" |> print



. , Python, , (x) -> x2



lambda x: x2



.





, Coconut:









match [head] + tail in [0, 1, 2, 3]:
    print(head, tail)
      
      







data Empty()
data Leaf(n)
data Node(l, r)

def size(Empty()) = 0

addpattern def size(Leaf(n)) = 1

addpattern def size(Node(l, r)) = size(l) + size(r)
      
      







{"list": [0] + rest} = {"list": [0, 1, 2, 3]}
      
      







range(10) |> map$(pow$(?, 2)) |> list
      
      







(| first_elem() |) :: rest_elems()
      
      







(f..g..h)(x, y, z)
      
      







x -> x ** 2
      
      







5 `mod` 3 == 2
      
      







", !" |> x -> x.replace('', 'Coconut') |> print
      
      







product = reduce$(*)
      
      







def factorial(n, acc=1):
    case n:
        match 0:
            return acc
        match _ is int if n > 0:
            return factorial(n-1, acc*n)
      
      







range(100) |> parallel_map$(pow$(2)) |> list
      
      



coconut-develop



(pip install coconut-develop



) Python 3.10, Coconut. Coconut v1.6.0.





Coconut Python Coconut :





, Python, Coconut . , , , , Coconut , , , : Coconut Python, Python, Coconut.





coconut - , Python, . Python Coconut, , Python — - Python.





, Python , Coconut . , .





(Sieve of Eratosthenes) - n, . , , , . , ( ) .





Python

Python : primes



sieve



. primes



sieve



.





from itertools import count, takewhile

def primes():
    def sieve(numbers):
        head = next(numbers)
        yield head
        yield from sieve(n for n in numbers if n % head)
    return sieve(count(2))

list(takewhile(lambda x: x < 60, primes()))
      
      



[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59]
      
      



sieve



count



, , 2 . sieve



(yield



) . (yield from



) sieve



, .





, numbers



next(numbers)



numbers



n for n in numbers if n % head



. , next



- : , .





list



, takewhile



, list



.





, - : , ..





Python Coconut

7 « »() Python Coconut.





1. lambda





lambda



->



.





from itertools import count, takewhile

def primes():
    def sieve(numbers):
        head = next(numbers)
        yield head
        yield from sieve(n for n in numbers if n % head)
    return sieve(count(2))

list(takewhile(x -> x < 60, primes()))
      
      



2.





f(g(h(d)))



-: d -> h -> g -> f



|>



.





from itertools import count, takewhile

def primes():
    def sieve(numbers):
        head = next(numbers)
        yield head
        yield from sieve(n for n in numbers if n % head)
    return sieve(count(2))

primes() |> ns -> takewhile(x -> x < 60, ns) |> list
      
      



3.





, , - . $



.





from itertools import count, takewhile

def primes():
    def sieve(numbers):
        head = next(numbers)
        yield head
        yield from sieve(n for n in numbers if n % head)
    return sieve(count(2))

primes() |> takewhile$(x -> x < 60) |> list
      
      



4.





, yield



, yield



yield from



. , ::



.





from itertools import count, takewhile

def primes():
    def sieve(numbers):
        head = next(numbers)
        return [head] :: sieve(n for n in numbers if n % head)
    return sieve(count(2))

primes() |> takewhile$(x -> x < 60) |> list
      
      



5.





, , , , . ::



, . , .





from itertools import count, takewhile

def primes():
    def sieve([head] :: tail):
        return [head] :: sieve(n for n in tail if n % head)
    return sieve(count(2))

primes() |> takewhile$(x -> x < 60) |> list
      
      



6.





. , . return



=



:



.





from itertools import count, takewhile

def primes() =
    def sieve([x] :: xs) = [x] :: sieve(n for n in xs if n % x)
    sieve(count(2))

primes() |> takewhile$(x -> x < 60) |> list
      
      



7.





, import



. , .. .





def primes() =
    def sieve([x] :: xs) = [x] :: sieve(n for n in xs if n % x)
    sieve(count(2))

primes() |> takewhile$(x -> x < 60) |> list
      
      



[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59]
      
      



. : primes



sieve



, sieve



. :





from itertools import count, takewhile

def primes():
    def sieve(numbers):
        head = next(numbers)
        yield head
        yield from sieve(n for n in numbers if n % head)
    return sieve(count(2))

list(takewhile(lambda x: x < 60, primes()))
      
      



:





def primes() =
    def sieve([x] :: xs) = [x] :: sieve(n for n in xs if n % x)
    sieve(count(2))

primes() |> takewhile$(x -> x < 60) |> list
      
      



, Coconut Haskell:





primes :: [Int]
primes = sieve [2..]
where
    sieve (x :: xs) = x : sieve (filter (\n -> n `rem` x /= 0) xs
    sieve []        = []
                                 
?> takewhile (<60) primes 
      
      







def quick_sort([]) = []

@addpattern(quick_sort)
def quick_sort([head] + tail) =
    """ , 
      ."""
    (quick_sort([x for x in tail if x < head])
    + [head]
    + quick_sort([x for x in tail if x >= head]))
    
quick_sort([3,6,9,2,7,0,1,4,7,8,3,5,6,7])
      
      



[0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 7, 7, 8, 9]
      
      







def factorial(0, acc=1) = acc

@addpattern(factorial)
def factorial(n is int, acc=1 if n > 0) =
    """ n!,  n -    >= 0."""
    factorial(n-1, acc*n)

def is_even(0) = True

@addpattern(is_even)
def is_even(n is int if n > 0) = is_odd(n-1)
def is_odd(0) = False

@addpattern(is_odd)
def is_odd(n is int if n > 0) = is_even(n-1)

factorial(6)  # 720
      
      







@recursive_iterator
def fib_seq() =
    """   ."""
    (1, 1) :: map((+), fib_seq(), fib_seq()$[1:])
            
fib_seq()$[:10] |> parallel_map$(pow$(?, 2)) |> list
      
      



[1, 1, 4, 9, 25, 64, 169, 441, 1156, 3025]
      
      







def zipwith(f, *args) =
    zip(*args) |> map$(items -> f(*items))
    
list(zipwith(lambda x: x > 4, [1,2,3,4,5,6,7,8,9,0]))
      
      



[False, False, False, False, True, True, True, True, True, False]
      
      



I hope that the clarity of the above examples will arouse the interest of readers and encourage them to engage in a deeper study of the FP paradigm. In fact, Coconut offers syntactic sugar, i.e. a series of code coding optimizations that make code functional by being a playground for testing ideas using the functional programming paradigm.





Reference materials:





  • Language website





  • Tutorial





  • Documentation





  • Github repository





  • Online interpreter





The post was prepared using information from the language website and materials from Anthony Kwong.








All Articles