forked from reem/python-monad
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmaybe.py
109 lines (86 loc) · 2.66 KB
/
maybe.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
"""
Jonathan Reem
Implementation of Data.Maybe from Haskell.
"""
# pylint: disable=C0103
from monad import Monad, MonadPlus, monadize
@monadize
class Maybe(Monad, MonadPlus):
"Implements the Maybe monad from Haskell."
NothingType = 'Nothing'
JustType = 'Just'
def __init__(self, maybe_type, value=None):
"WARNING: Should not be called directly."
self._maybe_type = maybe_type
if maybe_type == Maybe.JustType:
self._value = value
@classmethod
def Just(cls, value):
"Constructor for Just x values."
return cls(Maybe.JustType, value)
@classmethod
def Nothing(cls):
"Constructor for Nothing values."
return cls(Maybe.NothingType)
# Maybe as a Monad
def bind(self, bindee):
if self.kind == Maybe.JustType:
return bindee(self.value)
elif self.kind == Maybe.NothingType:
return Maybe.Nothing()
def return_m(self, val):
return Maybe.Just(val)
# Maybe as a MonadPlus
@property
def mzero(self):
return Maybe.Nothing()
def mplus(self, other):
if self.is_nothing:
return other
else:
return self
@property
def kind(self):
"Gets the kind of Maybe, Just or Nothing."
return self._maybe_type
@property
def is_nothing(self):
"Returns true if this is a Nothing"
return self.kind == Maybe.NothingType
@property
def is_just(self):
"Returns true if this is a Just"
return self.kind == Maybe.JustType
@property
def value(self):
"Gets the value if this is a Just, else throws an error."
if self.is_just:
return self._value
elif self.is_nothing:
raise ValueError("Tried to get value of a Nothing.")
def __str__(self):
if self.is_nothing:
return "Nothing()"
elif self.is_just:
return "Just({})".format(self.value)
def __repr__(self):
return str(self)
def maybe(default, func, maybe_val):
"""Takes a default value, a function, and a Maybe value.
If it's Nothing, return the default,
else, return the function applied to the value."""
if maybe_val.is_nothing:
return default
elif maybe_val.is_just:
return func(maybe_val.value)
def from_just(maybe_val):
"Will throw a ValueError if maybe_val is a Nothing."
return maybe_val.value
def from_maybe(default, maybe_val):
"""Takes a maybe_value and a default,
if the maybe_value is nothing returns the default,
else returns the value."""
try:
return maybe_val.value
except ValueError:
return default