                   :when (p v)]
                   (return v)))
 
-(defn m-when
-  "If the expression is true, returns the monadic value.
-
-  Otherwise, yields nil in a monadic context."
-  [b mv]
-  (if b
-    mv
-    (pure mv nil)))
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Haskell-style aliases and util functions.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defn <$>
+  "Alias of fmap."
+  ([f]
+     (fn [fv]
+       (p/fmap fv f)))
+  ([f fv]
+     (p/fmap fv f)))
+
+(defn <*>
+  "Performs a Haskell-style left-associative fapply."
+  ([af av]
+     (p/fapply af av))
+  ([af av & avs]
+     (reduce p/fapply af (cons av avs))))
+
+(defn >>=
+  "Performs a Haskell-style left-associative bind.
+
+  Example:
+    (>>= (just 1) (comp just inc) (comp just inc))
+    ;=> #<Just [3]>
+  "
+  ([mv f]
+     (bind mv f))
+  ([mv f & fs]
+     (reduce bind mv (cons f fs))))
+
+(defn =<<
+  "Same as the two argument version of `>>=` but with the
+  arguments interchanged."
+  [f mv]
+  (>>= mv f))
+
+(defn >=>
+  "Left-to-right composition of monads."
+  [mf mg x]
+  (#+clj  mlet
+   #+cljs cm/mlet [a (mf x)
+                   b (mg a)]
+                  (return b)))
+
+(defn <=<
+  "Right-to-left composition of monads.
+  Same as `>=>` with its first two arguments flipped."
+  [mg mf x]
+  (#+clj  mlet
+   #+cljs cm/mlet [a (mf x)
+                   b (mg a)]
+                  (return b)))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; State monad functions

                 ~next-mlet))))
    `(do ~@body)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Monadic functions
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defn join
  "Remove one level of monadic structure."
  [mv]
  (bind mv identity))

(defn =<<
  "Same as the two argument version of `>>=` but with the
  arguments interchanged."
  [f mv]
  (>>= mv f))

(defn >=>
  "Left-to-right composition of monads."
  [mf mg x]
  (#+clj  mlet
   #+cljs cm/mlet [a (mf x)
                   b (mg a)]
                  (return b)))

(defn <=<
  "Right-to-left composition of monads.

  Same as `>=>` with its first two arguments flipped."
  [mg mf x]
  (#+clj  mlet
   #+cljs cm/mlet [a (mf x)
                   b (mg a)]
                  (return b)))

(defn m-sequence
  "Given a non-empty collection of monadic values, collect
  their values in a vector returned in the monadic context.

      (require '[cats.types :as t])
      (require '[cats.core :as m])

      (m/m-sequence [(t/just 2) (t/just 3)])
      ;=> <Just [[2, 3]]>

      (m/m-sequence [(t/nothing) (t/just 3)])
      ;=> <Nothing>
  "
  [mvs]
  {:pre [(not-empty mvs)]}

    (return nil)
    (mzero)))

(defn join
  "Remove one level of monadic structure."
  [mv]
  (bind mv identity))

(defn fmap
  "Apply a function f to the value inside functor's fv
  preserving the context type."
