skip to navigation
skip to content

Not Logged In

fn 0.1.14

Implementation of missing features to enjoy functional programming in Python

Latest Version: 0.2.13

Fn.py: enjoy FP in Python

Despite the fact that Python is not pure-functional programming language, it's multi-paradigm PL and it gives you enough freedom to take credits from functional programming approach. There are theoretical and practical advantages to the functional style:

  • Formal provability
  • Modularity
  • Composability
  • Ease of debugging and testing

Fn.py library provides you with missing "batteries" to get maximum from functional approach even in mostly-imperative program.

More about functional approach from my Pycon UA 2012 talks: Functional Programming with Python.

Scala-style lambdas definition

from fn import _
from fn.iters import zipwith
from itertools import repeat

assert list(map(_ * 2, range(5))) == [0,2,4,6,8]
assert list(filter(_ < 10, [9,10,11])) == [9]
assert list(zipwith(_ + _)([0,1,2], repeat(10))) == [10,11,12]

More examples of using _ you can find in test cases declaration (attributes resolving, method calling, slicing).

Streams and infinite sequences declaration

Lazy-evaluated scala-style streams. Basic idea: evaluate each new element "on demand" and share calculated elements between all created iterators. Stream object supports << operator that means pushing new elements when it's necessary.

Simplest cases:

from fn import Stream

s = Stream() << [1,2,3,4,5]
assert list(s) == [1,2,3,4,5]
assert s[1] == 2
assert s[0:2] == [1,2]

s = Stream() << range(6) << [6,7]
assert list(s) == [0,1,2,3,4,5,6,7]

def gen():
    yield 1
    yield 2
    yield 3

s = Stream() << gen << (4,5)
assert list(s) == [1,2,3,4,5]

Lazy-evaluated stream is useful for infinite sequences, i.e. fibonacci sequence can be calculated as:

from fn import Stream
from fn.iters import take, drop, map
from operator import add

f = Stream()
fib = f << [0, 1] << map(add, f, drop(1, f))

assert list(take(10, fib)) == [0,1,1,2,3,5,8,13,21,34]
assert fib[20] == 6765
assert fib[30:35] == [832040,1346269,2178309,3524578,5702887]

High-level operations with functions

fn.F is a useful function wrapper to provide easy-to-use partial application and functions composition.

from fn import F, _
from operator import add, mul

# F(f, *args) means partial application
# same as functools.partial but returns fn.F instance
assert F(add, 1)(10) == 11

# F << F means functions composition,
# so (F(f) << g)(x) == f(g(x))
f = F(add, 1) << F(mul, 100)
assert list(map(f, [0, 1, 2])) == [1, 101, 201]
assert list(map(F() << str << (_ ** 2) << (_ + 1), range(3))) == ["1", "4", "9"]

You can find more examples for compositions usage in fn._ implementation source code.

fn.op.apply executes given function with given positional arguments in list (or any other iterable). fn.op.flip returns you function that will reverse arguments order before apply.

from fn.op import apply, flip
from operator import add, sub

assert apply(add, [1, 2]) == 3
assert flip(sub)(20,10) == -10
assert list(map(apply, [add, mul], [(1,2), (10,20)])) == [3, 200]

Itertools recipes

fn.iters module consists from two parts. First one is "unification" of lazy functionality for few functions to work the same way in Python 2+/3+:

  • map (returns itertools.imap in Python 2+)
  • filter (returns itertools.ifilter in Python 2+)
  • reduce (returns functools.reduce in Python 3+)
  • zip (returns itertools.izip in Python 2+)
  • range (returns xrange in Python 2+)
  • filterfalse (returns itertools.ifilterfalse in Python 2+)
  • zip_longest (returns itertools.izip_longest in Python 2+)

Second part of module is high-level recipes to work with iterators. Most of them taken from Python docs and adopted to work both with Python 2+/3+. Such recipes as drop, takelast, droplast, splitat, splitby I have already submitted as docs patch which is review status just now.

  • take, drop
  • takelast, droplast
  • head, tail
  • consume
  • nth
  • padnone, ncycles
  • repeatfunc
  • grouper, powerset, pairwise
  • roundrobin
  • partition, splitat, splitby
  • flatten
  • zipwith
  • iter_except

More information about use cases you can find in docstrings for each function in source code and in test cases.

Functional style for error-handling

  • Maybe
  • Either

TODO: Implementation, code samples

Trampolines decorator

Workaround for dealing with TCO without heavy stack utilization.

TODO: Implementation, code samples and documented theory.

Installation

To install fn.py, simply:

$ pip install fn

Or, if you absolutely must:

$ easy_install fn

You can also build library from source

$ git clone https://github.com/kachayev/fn.py.git
$ cd fn.py
$ python setup.py install

Work in progress (!)

"Roadmap":

  • Error handling (Maybe, Either from Haskell, Option from Scala etc)
  • Trampolines decorator
  • Add to fn.iters module foldl, foldr, findelem, findindex
  • C-accelerator for most modules

Ideas to think about:

  • "Pipeline" notation for composition (back-order): F() >> list >> partial(map, int)
  • Curried function builder to simplify lambda arg1: lambda arg2: ...
  • Scala-style for-yield loop to simplify long map/filter blocks

Contribute

  1. Check for open issues or open a fresh issue to start a discussion around a feature idea or a bug.
  2. Fork the repository on Github to start making your changes to the master branch (or branch off of it).
  3. Write a test which shows that the bug was fixed or that the feature works as expected.

History

18.01.2012

  • Added 22 itertools recipes to fn.iters
  • Documentation is converted to RST

17.01.2012

  • Unit tests coverage for fn.stream.Stream
  • _StreamIterator works fine both in Python 2/3

16.01.2012

  • Finished underscore module functionality
  • Test cases for all implemented modules/functions
  • Update in Readme file with several fixes
  • Get rid of F.flip classmethod in pref. for simple building blocks
  • Optimized version for fn.op.flip operator

14.01.2012

  • Simplest Stream implementation
  • Code samples for streams, labdas (_) and functions compositions
  • Plan, contribute section in readme file

13.01.2012

  • Full list of ideas on paper
  • Repository is created
  • Initial commit
 
File Type Py Version Uploaded on Size
fn-0.1.14.tar.gz (md5) Source 2013-01-18 11KB
  • Downloads (All Versions):
  • 8 downloads in the last day
  • 346 downloads in the last week
  • 1517 downloads in the last month
  • Author: Alexey Kachayev
  • Home Page: https://github.com/kachayev/fn.py
  • License:
    Copyright 2013 Alexey Kachayev
    
       Licensed under the Apache License, Version 2.0 (the "License");
       you may not use this file except in compliance with the License.
       You may obtain a copy of the License at
    
           http://www.apache.org/licenses/LICENSE-2.0
    
       Unless required by applicable law or agreed to in writing, software
       distributed under the License is distributed on an "AS IS" BASIS,
       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
       See the License for the specific language governing permissions and
       limitations under the License.
  • Package Index Owner: kachayev
  • DOAP record: fn-0.1.14.xml