Skip to content

Instantly share code, notes, and snippets.

@tokland
Created January 24, 2012 19:22
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tokland/1672014 to your computer and use it in GitHub Desktop.
Save tokland/1672014 to your computer and use it in GitHub Desktop.
Playing (informally) with the Either monad in Python
# Rationale: How to chain functions with type (a -> transformation_of_a) #
# as they were (a -> a)?
#
# If the functions were "normal" (a -> a), we'd write simply: fun3(fun2(fun1(1)))
def fun1(x):
return ("ok", 1*x) if x > 1 else ("fail", "fun1: value of x is ugly: %s" % x)
def fun2(x):
return ("ok", 2*x) if x > 2 else ("fail", "fun2: value of x is ugly: %s" % x)
def fun3(x):
return ("ok", 3*x) if x > 7 else ("fail", "fun3: value of x is ugly: %s" % x)
# Option1: Wrapper
def w(func, value):
if value[0] == "ok":
return func(value[1])
elif value[0] == "fail":
return value
else:
raise ValueError(value)
print(w(fun3, w(fun2, fun1(1))))
print(w(fun3, w(fun2, fun1(2))))
print(w(fun3, w(fun2, fun1(3))))
print(w(fun3, w(fun2, fun1(4))))
# Option1b: Create wrapper chain.
def reduce_w(funcs, initial_value):
head, *tail = funcs
value = head(initial_value)
for func in tail:
value = w(func, value)
return value
print("using reduce_w:", reduce_w([fun1, fun2, fun3], 2))
# Option2: Lift functions
def lift(func):
def _wrapper(value):
return w(func, value)
return _wrapper
print("using lifting:", lift(fun3)(lift(fun2)(fun1(2))))
# Option2b: Use lifted functions and start by "lifting" the initial value (like Haskell's "return")
lfun1, lfun2, lfun3 = map(lift, [fun1, fun2, fun3])
def prepare(value):
return ("ok", value)
print("using lifting 2:", lfun3(lfun2(lfun1(prepare(2)))))
# ('fail', 'fun1: value of x is ugly: 1')
# ('fail', 'fun2: value of x is ugly: 2')
# ('fail', 'fun3: value of x is ugly: 6')
# ('ok', 24)
# using reduce_w: ('fail', 'fun2: value of x is ugly: 2')
# using lifting: ('fail', 'fun2: value of x is ugly: 2')
# using lifting 2: ('fail', 'fun2: value of x is ugly: 2')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment