Skip to main content

Functional programming tools for python. Putting the fun in functional programming 😉

Project description

Functionali

functional programming tools for python. Putting the fun in functional programming 😉

codecov Documentation Status

Functional programming is a fundamentally different way of solving problems, and once It clicks, it's pure joy after that. A lot of ideas in this library have been taken from Clojure and Haskell, so the credit goes to those languages. If you find your favorite function missing, or find ways to improve this project, I'd love to hear it.

Documentation

wiki

Installation

pip install functionali 

Features

  • Polymorphic functions that operate on all sequences. Including dictionaries.
  • A bunch of commonly used predicates that enhance readability, especially when used with filters.

A note on how functionali deals with dictionaries.

As of now, all sequence traversing like first and rest functions treat dictionaries as a nested tuple of keys and values. Here's an example.

>>> d = {1:"a"}
>>> first(d)
((1, "a"),)

while this is convenient for traversing dicts, it makes certain functions like contains rather awkward, since you as the user, would have to explicity convert the tuple back to a dict before passing it in. (This might change in future)

functional programming is powerful

One of my favorite Functional implementations of an algorithm is insertion sort, here's how simple it

>>> from functionali import foldr, insert
>>> def insertion_sort(iterable):
...     return foldr(insert, iterable, [])

>>> insertion_sort([3,2,1])
(1, 2, 3)

# even works with dictionaries
>>> insertion_sort({3:"c", 1: "a", 2: "b"})  
((1, 'a'), (2, 'b'), (3, 'c'))

# and strings
>>> insertion_sort("cbdasdf")
('a', 'b', 'c', 'd', 'd', 'f', 's')
>>> "".join(insertion_sort("cbdasdf"))
'abcddfs' # better?

functional programs are flexible

Let's say you wanted to find a number that was divisible by The following numbers 1,2,3,4,5,6,7,8,9,10 One way to solve it is a bunch of nested if Statements and we all know how brittle those can be.

Let's see the functional way.

>>> from functionali import is_divisible_by, all_predicates
>>> my_filter = all_predicates(*map(is_divisible_by,[1,2,3,4,5,6,7,8,9,10]))
>>> list(filter(my_filter,range(1,10000)))
[2520, 5040, 7560]

Now let's say the boss decides that He wants the numbers that are not Divisible by all these numbers

>>> from functionali import complement
>>> list(filter(complement(my_filter),range(1,10000)))
[... 2515, 2516, 2517, 2518, 2519, 2521, 2522, 2523, 2524...] # Snipped for brevity 
# note that 2520 is not present

The boss comes in again and he says that he Doesn't want numbers that are divisible by ALL these numbers but instead, ANY of these numbers [1,2,3,4,5,6,7,8,9,10]

>>> from functionali import some_predicates
>>> my_filter = some_predicates(*map(is_divisible_by,[1,2,3,4,5,6,7,8,9,10]))
>>> list(filter(complement(my_filter),range(1,10000)))
[]

The boss realizes that all numbers are divisible by 1 and he tells you to Remove 1

>>> my_filter = some_predicates(*map(is_divisible_by,[2,3,4,5,6,7,8,9,10]))   
>>> list(filter(complement(my_filter),range(1,10000)))
[1, 11, 13, 17, 19, 23, 29, 31...] # ,Snipped for brevity

A few more examples

Functionali provides functions to traverse sequences(Including dictionaries), Some of the most useful ones are first, rest, last,butlast, take, drop

from functionali import first, rest, last, butlast, take, drop

>>> first([1,2,3,4,5])
    1

>>> first({1:"a", 2:"b"})
    (1, "a")

>>> last([1,2,3,4])
    4

>>> list(rest([1,2,3,4,5]))
    [2, 3, 4, 5]

>>> butlast([1,2,3]) # returns all elements except the last element
    (1,2)

>>> take(3, [1,2,3,4,5])
    (1, 2, 3)

>>> drop(3, [1,2,3,4,5])
    (4,5)

There are functions that construct new sequences like cons, conj, concat, insert

from functionali import cons, conj, concat, insert
>>> cons(5, [1,2,3,4])
    deque([5, 1, 2, 3, 4]) # 5 is the 'head' of the new list.

# adds element to the iterable, at the appropriate end.
>>> conj([1,2,3,4],5) # similar to Clojure's conj
    [1, 2, 3, 4, 5]

    # Adds to the left of a deque.
>>> conj(deque([1,2]), 3,4)
    deque([4, 3, 1, 2])

# Add items to the end of the iterable.
>>> concat([1,2,3,4],5)
    [1, 2, 3, 4, 5]

>>> concat(deque([1,2]), 3,4)
    deque([1, 2, 3, 4])

# Inserts 3 right before the first element
# in the iterable (here:4) that is greater than 3
>>> insert(3, [1,2,4,2])
    (1,2,3,4,2)

Functionali also comes with a number of useful predicates (if You can't find something you're looking for, make a pull request.) These can be combined in various ways. for example.

from functionali import is_even, is_prime, take_while
>>> list(filter(is_even,[1,2,3,4])
    [2,4]

>>> take_while(is_prime, [2,3,5,4,6,5])) # Constructs a list while is_prime is true.
    [2,3,5]

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

functionali-0.3.0.tar.gz (14.2 kB view details)

Uploaded Source

Built Distribution

functionali-0.3.0-py3-none-any.whl (16.1 kB view details)

Uploaded Python 3

File details

Details for the file functionali-0.3.0.tar.gz.

File metadata

  • Download URL: functionali-0.3.0.tar.gz
  • Upload date:
  • Size: 14.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.1.6 CPython/3.8.9 Windows/10

File hashes

Hashes for functionali-0.3.0.tar.gz
Algorithm Hash digest
SHA256 8c82b12590af2b1feba5ae2003efdb61a79a651ecf2c2f1f3b42491238e47267
MD5 710418a3b9766157d3fa7b46c5a48e31
BLAKE2b-256 3fa152bb38d30d9835123f80ac02e2326462581afa8e997f2e94a32baf66a5b0

See more details on using hashes here.

File details

Details for the file functionali-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: functionali-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 16.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.1.6 CPython/3.8.9 Windows/10

File hashes

Hashes for functionali-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e48619fdc3dc2b411f3a6f9b14a4546f0ae60cd7132882aea1b3d42bbc6da491
MD5 3f41f8fac254a33fbdfd7bd1e21d8093
BLAKE2b-256 3f501323ed7dfdca19bb5a6dc5070492ee256612be0c978753a0e15196e9433e

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page