Created
January 24, 2012 19:22
-
-
Save tokland/1672014 to your computer and use it in GitHub Desktop.
Playing (informally) with the Either monad in Python
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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