Skip to content

Instantly share code, notes, and snippets.

@kdungs
Last active February 21, 2016 12:42
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 kdungs/7c08fbc7e97fd4505459 to your computer and use it in GitHub Desktop.
Save kdungs/7c08fbc7e97fd4505459 to your computer and use it in GitHub Desktop.
Define a Check monad and corresponding functions in Python. Now also a repo: https://github.com/kdungs/python-mcheck
""" Define a Check monad and corresponding functions.
"""
from functools import partial
class Check:
""" This super class is not really necessary but helps make the structure
clear.
data Check a = Pass a | Fail Message
"""
pass
class Pass(Check):
def __init__(self, value):
self.value = value
class Fail(Check):
def __init__(self, message):
self.message = message
def is_(t, x):
""" Check whether the type of a given x is a given type t.
"""
return type(x) is t
is_check = partial(is_, Check)
is_pass = partial(is_, Pass)
is_fail = partial(is_, Fail)
def return_(x):
""" Monadic return for the Check monad.
return :: a -> m a
return = Pass
"""
return Pass(x)
def bind(f):
""" Monadic bind for the Check monad.
(>>=) :: m a -> (a -> m b) -> m b
Fail x >>= f = Fail x
Pass x >>= f = f x
"""
def bind_impl(x):
if is_fail(x):
return x
if is_pass(x):
return f(x.value)
raise ValueError('Check has to be of type Pass | Fail.')
return bind_impl
def compose(f, g):
""" Kleisli composition of two (Check-)monadic functions f and g.
(>=>) :: (a -> m b) -> (b -> m c) -> (a -> m c)
"""
def compose_impl(x):
return bind(g)(f(x))
return compose_impl
def lift(f, message):
""" Lifts a boolean function into the realm of the Check monad.
lift :: (a -> bool) -> (a -> Check a)
"""
def lift_impl(x):
if f(x):
return return_(x)
return Fail(message)
return lift_impl
import check as c
def is_positive(x):
return x > 0
def is_even(x):
return not x & 1
check_positive = c.lift(is_positive, 'Number has to be positive.')
check_even = c.lift(is_even, 'Number has to be even.')
check_evenpositive = c.compose(check_even, check_positive)
print(check_positive(-5).message)
print(check_positive(5).value)
print(check_even(1).message)
print(check_even(2).value)
print(check_evenpositive(1).message)
print(check_evenpositive(2).value)
print(check_evenpositive(-1).message)
print(check_evenpositive(-2).message)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment