Package: lawvere
What ?Functionnal Tool: (de)composition with type checking, multiple dispatch.Why ?There is a lot of functionnal tools in python: toolz, funcy, fn.py, Pymonads…They are great but none of them do type checking which, in my opinion, is a big loss from functionnal paradigm view.How ?With a complex and unmaintenable api: a single decorator called“arrow”.For atechnicalexplanation of arrows you can look at:Understanding arrowsFor atheoricalexplanation:“Conceptual Mathematics: A First Introduction to Categories”[F. William Lawvere, Stephen H. Schanuel] is good start.PrerequisitesI strongly recommand to have at least notions about:lambda calculi (Currying)tuples in algebra notations (e.g.signatures)basics of graph theory (related to category theory - morphisms, domain, codomain…)Table of ContentsInstallationUsageDevelopmentInstallationInstall it from pypi:pip install lawvereor from sources:git clone git@github.com:apieum/lawvere.git
cd lawvere
python setup.py installUsageQuick start:for impatientsarrowtake only two optionnal arguments:thedomainorsource: it’s a tuple of types (or just a type in case of 1-tuple)the codomain ortarget: (a single type)It returns a function decorator.Syntax is compatible for python 2.7 to 3.x..
In case you target 3.x versions only you can use annotations instead of “arrow” arguments.
“arrow” arguments override annotations.Code compatible with 2.x and 3.x python versions.fromlawvereimportarrow# obviously you don't need to use named parameters# it's just to illustrate their meaning.@arrow(domain=(int,int),codomain=int)defadd(x,y):returnx+y# currying:add2=add(2)assertadd2(3)==5assertadd(1)(2)==3# successive calls# composition (pipe):# pass the result of first function to secondadd4=add2>>add2assertadd4(1)==5# composition (circle):# pass result of add(1) into add4add5=add4<<add(1)assertadd5(5)==10# composed functions are tuples:assertisinstance(add4,tuple)assertadd5[1]==add4# equality is checked over signatures:assertadd(1)==add(1)assertadd5==add(1)>>add2>>add2# operator precedence:assertadd5==add(1)>>(add2<<add2)assertadd5==add2>>add2<<add(1)# Type Checking:type_checked=Falsetry:add('a','b')=='ab'exceptTypeError:type_checked=Trueasserttype_checked,'add should not exists for str types'# dispatch register# concat inherit arrow properties@add.register((str,str),str)defconcat(x,y):return"%s%s"%(x,y)# can still call/curry... concatassertconcat('a')('b')=='a b'# add with str call concatassertadd('a')==concat('a')# Concat is only defined for strtype_checked=Falsetry:assertconcat(1,2)==3exceptTypeError:type_checked=Trueasserttype_checked,'concat should not exists for int types'# Type Checking when composing:try:add>>concat(y='b')exceptTypeErrorasexc:message=str(exc)# hope message is clear :)assertmessage=="Cannot compose add -> int with concat(x:str=Undefined, y:str=b)"# if composition was circle message would be:# ... concat -> str with add(x:int=Undefined, y:int=Undefined)Code compatible with 3.x versions only.fromlawvereimportarrow@arrowdefadd(x:int,y:int)->int:returnx+y# identical use as Python 2 ## Type Checking:type_checked=Falsetry:add('a','b')=='ab'exceptTypeError:type_checked=Trueasserttype_checked,'add should not exists for str types'# dispatch@add.registerdefconcat(x:str,y:str)->str:return"%s%s"%(x,y)assertconcat('a','b')=='a b'# now add exists for str types:assertadd('a','b')=='a b'# type is also checked when composing... see python 2 ex.DevelopmentYour feedback, code review, improvements or bugs, and help to document is appreciated.
You can contact me by mail: apieum [at] gmail [dot] comTest recommended requirements:pip install -r dev-requirements.txtSometimes –spec-color doesn’t function. Uninstall nosespec and nosecolor then reinstall nosecolor and nosespec separatly in this order (nosecolor first).Launch tests:git clone git@github.com:apieum/lawvere.git
cd lawvere
nosetests --with-spec --spec-color ./lawvere
# or with watch
# nosetests --with-spec --spec-color --with-watch ./lawvere