summaryrefslogtreecommitdiff
path: root/topics
diff options
context:
space:
mode:
authorArun Isaac2022-09-16 16:30:40 +0530
committerArun Isaac2022-09-16 16:30:40 +0530
commit72882e7d5206fed073c9f910a914a37c4e928817 (patch)
tree1aafd4a95512d5069a8b15f1255b7292c9c95584 /topics
parent304de26b8f10fbd0b03467895ee2f348fddd41f7 (diff)
downloadgn-gemtext-72882e7d5206fed073c9f910a914a37c4e928817.tar.gz
Explain the maybe monad.
Diffstat (limited to 'topics')
-rw-r--r--topics/coding-guidelines.gmi1
-rw-r--r--topics/maybe-monad.gmi52
2 files changed, 53 insertions, 0 deletions
diff --git a/topics/coding-guidelines.gmi b/topics/coding-guidelines.gmi
index 47cb697..1d5dc5a 100644
--- a/topics/coding-guidelines.gmi
+++ b/topics/coding-guidelines.gmi
@@ -3,6 +3,7 @@
We aim to adhere to the following coding guidelines.
=> /topics/use-exceptions-to-indicate-errors Exceptions, not None return values
+=> /topics/maybe-monad Maybe monad, not None values
=> /topics/better-logging Log messages
This document is an index of other documents describing coding guidelines. Add more here as you write/discover them.
diff --git a/topics/maybe-monad.gmi b/topics/maybe-monad.gmi
new file mode 100644
index 0000000..5ec582c
--- /dev/null
+++ b/topics/maybe-monad.gmi
@@ -0,0 +1,52 @@
+# Maybe monad
+
+None values are values that represent the absence of a value. This leads to a proliferation of conditionals and special cases in the code, and is a terrible way to represent the absence of a value. We need something better. Enter the maybe monad.
+
+For a detailed case against None values, read
+=> https://www.lucidchart.com/techblog/2015/08/31/the-worst-mistake-of-computer-science/
+
+Consider the following code snippet where we print a value if it is not None.
+```
+def print_unless_none(x):
+ if x is not None:
+ print(x)
+
+foo = 1
+bar = None
+print_unless_none(foo)
+print_unless_none(bar)
+```
+
+Rewriting the same code using the maybe monad, we can avoid the conditional check making the code more concise and more robust against bugs.
+```
+from pymonad.maybe import Just, Nothing
+
+foo = Just(1)
+bar = Nothing
+foo.bind(print)
+bar.bind(print)
+```
+
+Monads may also be passed through a chain of function calls without any condition checking in between. If foo were Nothing, the entire sequence of operations would be skipped with no error raised. Notice how this is much cleaner than interleaving the code with if conditions checking for None intermediate values.
+```
+foo = Just(1)
+foo.map(lambda x: 1 + x) \
+ .map(lambda x: x**2) \
+ .bind(print)
+```
+
+Finally, let's put all this together in a practical example using the MonadicDictCursor from genenetwork. Consider the following code using the DictCursor. The column foo may contain NULL values, and we need to check for them.
+```
+with conn.cursor(MySQLdb.cursors.DictCursor) as cursor:
+ cursor.execute("SELECT foo FROM bar")
+ for row in cursor.fetchall():
+ if row["foo"] is not None:
+ print(row["foo"])
+```
+But, with the MonadicDictCursor, the row object is a MonadictDict where all values are monadic. We therefore do not need any special conditional checks.
+```
+with conn.cursor(utility.monads.MonadicDictCursor) as cursor:
+ cursor.execute("SELECT foo FROM bar")
+ for row in cursor.fetchall():
+ row["foo"].bind(print)
+```