i have a function, m_chain, which refers to two functions bind
and unit
which are not defined. i want to wrap this function in some context which provides definitions for these functions - you can think of them as interfaces for which i want to dynamically provide an implementation.
def m_chain(*fns):
"""what this function does is not relevant to the question"""
def m_chain_link(chain_expr, step):
return lambda v: bind(chain_expr(v), step)
return reduce(m_chain_link, fns, unit)
In Clojure, this is done with macros. what are some elegant ways of doing this in python? i have considered:
- polymorphism: turn m_chain into a method referring to
self.bind
andself.unit
, whose implementations are provided by a subclass - implementing the
with
interface so i can modify the environment map and then clean up when i'm done - changing the signature of m_chain to accept unit and bind as arguments
- requiring usage of m_chain be wrapped by a decorator which will do something or other - not sure if this even makes sense
ideally, i do not want to modify m_chain at all, i want to use the definition as is, and all of the above options require changing the definition. This is sort of important because there are other m_* functions which refer to additional functions to be provided at runtime.
How do i best structure this so i can nicely pass in implementations of bind and unit? its important that the final usage of m_chain be really easy to use, despite the complex implementation.
edit: here's another approach which works, which is ugly as all hell because it requires m_chain be curried to a function of no args. but this is a minimum working example.
def domonad(monad, cmf):
bind = monad['bind']; unit = monad['unit']
return cmf()
identity_m = {
'bind':lambda v,f:f(v),
'unit':lambda v:v
}
maybe_m = {
'bind':lambda v,f:f(v) if v else None,
'unit':lambda v:v
}
>>> domonad(identity_m, lambda: m_chain(lambda x: 2*x, lambda x:2*x)(2))
8
>>> domonad(maybe_m, lambda: m_chain(lambda x: None, lambda x:2*x)(2))
None