pythonic-fp.fptools API¶
FP Tools Package¶
Pythonic FP - Functional Programming Tools
Tools to aid with functional programming in Python yet still endeavoring to remain Pythonic.
Subtypeable Boolean¶
Class Bool - Subclassable Boolean
Python does not permit bool to be subclassed, but int
can be subclassed.
Under-the-hood a bool
is just an int
. The Bool class inherits from
int
and relies on the underlying truthiness and falsiness
of 1
and 0
.
The Truth(truth: str)
and Lie(lie: str)
subclass constructors
produce singletons based on their input parameters. When using type hints,
declare variables of these types as type Bool
. Best practices when
used with these subclasses are:
use == or != for pure Boolean comparisons
use is or not is if the type of truth matters
only use Bool() as a type, never as a constructor
when using Python shortcut logic remember
an instance of
Truth
is truthyan instance of
Lie
is falsyshortcut logic is lazy
the last truthy thing evaluated is returned
and is not converted to a
bool
the not statement converts a
Bool
to an actualbool
- class pythonic_fp.fptools.bool.Bool¶
Subclassable Boolean-like class.
- class pythonic_fp.fptools.bool.Lie(lie='LIE')¶
Falsy singleton Bool subclass.
- :: note:
When using type hints, declare variables Bool, not Lie.
- class pythonic_fp.fptools.bool.Truth(truth='TRUTH')¶
Truthy singleton Bool subclass.
- :: note:
When using type hints, declare variables Bool, not Truth.
Function Tools¶
Pythonic FP - FP tools for functions
Not a replacement for the std library’s functools which is more about modifying function behavior through decorators than functional composition and application.
FP utilities to manipulate and partially apply functions
function swap: Swap the arguments of a 2 argument function
function it: Function returning an iterator of its arguments
function sequenced: Convert function to take a sequence of its arguments
function negate: Transforms a predicate to its negation
function partial: Returns a partially applied function
- pythonic_fp.fptools.function.it(*args)¶
Function returning an iterator of its arguments.
- Return type:
Iterator
[A
]
- pythonic_fp.fptools.function.negate(f)¶
Take a predicate and return its negation.
- Return type:
Callable
[ParamSpec
,bool
]
- pythonic_fp.fptools.function.partial(f, *args)¶
Partially apply arguments to a function, left to right.
type-wise the only thing guaranteed is the return type
best practice is to cast the result immediately
- Return type:
Callable
[…,R
]
- pythonic_fp.fptools.function.sequenced(f)¶
Convert a function with arbitrary positional arguments to one taking a tuple of the original arguments.
was awaiting typing and mypy “improvements” to ParamSpec
return type: Callable[tuple[P.args], R] ???
return type: Callable[[tuple[P.args]], R] ???
not going to happen - https://github.com/python/mypy/pull/18278
TODO: Look into replacing this function with a Callable class?
- Return type:
Callable
[tuple
[Any
],R
]
- pythonic_fp.fptools.function.swap(f)¶
Swap arguments of a two argument function.
- Return type:
Callable
[V
,U
,R
]
Lazy Function Evaluation¶
Pythonic FP - Lazy function evaluation
Delayed function evaluations. FP tools for “non-strict” function evaluations. Useful to delay a function’s evaluation until some inner scope.
Non-strict delayed function evaluation:
class Lazy: Delay evaluation of functions taking & returning single values
function lazy: Delay evaluation of functions taking any number of values
function real_lazy: Version of
lazy
which caches its result
- class pythonic_fp.fptools.lazy.Lazy(f, d, pure=True)¶
Delayed evaluation of a singled valued function.
Class instance delays the executable of a function where
Lazy(f, arg)
constructs an object that can evaluate the Callablef
with its argument at a later time.first argument
f
taking values of type~D
to values of type~R
second argument
arg: ~D
is the argument to be passed tof
where the type
~D
is thetuple
type of the argument types tof
function is evaluated when the
eval
method is calledresult is cached unless
pure
is set toFalse
returns True in Boolean context if evaluated
Usually use case is to make a function “non-strict” by passing some of its arguments wrapped in Lazy instances.
- eval()¶
Evaluate function with its argument.
evaluate function
cache result or exception if
pure == True
reevaluate if
pure == False
- Return type:
None
- get(alt=None)¶
Get result only if evaluated and no exceptions occurred, otherwise return an alternate value.
A possible use case would be if the calculation is expensive, but if it has already been done, its result is better than the alternate value.
- Return type:
Union
[-R
,Never
]
- get_exception()¶
Get result only if evaluate and exceptional.
- Return type:
MayBe
[Exception
]
- get_result()¶
Get result only if evaluated and not exceptional.
- Return type:
MayBe
[-R
]
- got_exception()¶
Return true if Lazy raised exception.
- Return type:
MayBe
[bool
]
- got_result()¶
Return true if an evaluated Lazy did not raise an exception.
- Return type:
MayBe
[bool
]
- pythonic_fp.fptools.lazy.lazy(f, *args, **kwargs)¶
Delayed evaluation of a function with arbitrary positional arguments.
Function returning a delayed evaluation of a function of an arbitrary number of positional arguments.
first positional argument
f
takes a functionnext positional arguments are the arguments to be applied later to
f
f
is reevaluated whenevereval
method of the returnedLazy
is called
any kwargs passed are ignored
if
f
needs them, then wrapf
in another function
- Return type:
Lazy
[tuple
[Any
, …],R
]
- pythonic_fp.fptools.lazy.real_lazy(f, *args, **kwargs)¶
Cached delayed evaluation of a function with arbitrary positional arguments.
Function returning a delayed evaluation of a function of an arbitrary number of positional arguments.
first positional argument
f
takes a functionnext positional arguments are the arguments to be applied later to
f
f
is evaluated wheneval
method of the returnedLazy
is calledf
is evaluated only once with results cached
any kwargs passed are ignored
if
f
needs them then wrapf
in another function
- Return type:
Lazy
[tuple
[Any
, …],R
]
Singletons¶
Pythonic FP - Collection of singleton classes
- final class pythonic_fp.fptools.singletons.Nada¶
Singleton class representing & propagating failure.
singleton
_nada: nada = Nada()
represents a non-existent valuereturns itself for arbitrary method calls
returns itself if called as a Callable with arbitrary arguments
interpreted as an empty container by standard Python functions
warning: non-standard equality semantics
comparison compares true only when 2 non-missing values compare true
thus
a == b
means two non-missing values compare as equal
usage
import
Nada
and theneither use
Nada()
directlyor define
_nada: Final[Nada] = Nada()
don’t export it
start propagating failure by setting a propagating value to Nada()
works best when working with expression
failure may fail to propagate
for a function/method with just side effects
engineer Nada() to fail to trigger side effects
test for failure by comparing a result to
Nada()
itself usingis
andis not
propagate failure through a calculation using
==
and!=
the
Nada()
value never equals itselfand never equals anything else
- nada_get(alt=Sentinel('Nada'))¶
Get an alternate value, defaults to
Nada()
.- Return type:
Any
- class pythonic_fp.fptools.singletons.NoValue¶
Singleton class representing a missing value.
similar to
None
butwhile
None
represents “returned no values”NoValue()
represents the absence of a value
usage
import NoValue
frompythonic-fp.fptools.singletons
and theneither use
NoValue()
directlyor define
_noValue: Final[NoValue] = NoValue()
don’t export it
compare using
is
andis not
not
==
or!=
None
means returned no values, soNone == None
makes senseif one or both values are missing, then what is there to compare?
- final class pythonic_fp.fptools.singletons.Sentinel(sentinel_name)¶
Singleton classes representing a sentinel values.
intended for library code, not to be exported/shared between modules
otherwise some of its intended typing guarantees may be lost
useful substitute for
None
as a hidden sentinel valueallows
None
to be stored in data structuresallows end users to choose to use
None
or()
as sentinel valuesalways equals itself (unlike
NoValue
)
usage
import Sentinel and then either
define
_my_sentinel: Final[Sentinel] = Sentinel('my_sentinel')
or use
Sentinel('my_sentinel')
directly
compare using either
is
andis not
or==
and!=
the
Sentinel()
value always equals itselfand never equals anything else, especially other sentinel values
State Monad¶
Pythonic FP - State Monad
Handling state functionally.
##### class State - Classic FP State Monad
A pure FP immutable implementation for the State Monad.
translated to Python from the book “Functional Programming in Scala”
authors Chiusana & Bjarnason
run “action” returns a tuple
(a, s)
reversed to the typeState[S, A]
the standard convention seen in the FP community
another “factoid” to remember
choose the name
bind
instead offlatmap
the
flatmap
name is misleading for non-container-like monadsflatmap
name too long,bind
shorter to typewithout “do-notation”, code tends to march to the right
typing for the
modify
class method may be a bit suspect
- class pythonic_fp.fptools.state.State(run)¶
Data structure generating values while propagating changes of state.
class
State
represents neither a state nor (value, state) pairit wraps a transformation old_state -> (value, new_state)
the
run
method is this wrapped transformationbind
is just state propagating function composition
- eval(init)¶
Evaluate the Monad via passing an initial state.
- Return type:
~A
- static get()¶
Set run action to return the current state
the current state is propagated unchanged
current value now set to current state
will need type annotation
- Return type:
State
[ST
,ST
]
- static modify(f)¶
Modify previous state.
like put, but modify previous state via
f
will need type annotation
mypy has no “a priori” way to know what ST is
- Return type:
State
[ST
,tuple
]
- static put(s)¶
Manually insert a state.
THe run action.
ignores previous state and swaps in a new state
assigns a canonically meaningless value to current value
- Return type:
State
[ST
,tuple
]