   "Lifts a function with the given fixed number of arguments to a
   monadic context.
 
-      (require '[cats.monad.maybe :as maybe])
-      (require '[cats.core :as m])
-
-      (def monad+ (m/lift-m 2 +))
+      (def monad+ (lift-m 2 +))
 
       (monad+ (maybe/just 1) (maybe/just 2))
-      ;=> <Just [3]>
+      ;; => <Just [3]>
 
       (monad+ (maybe/just 1) (maybe/nothing))
-      ;=> <Nothing>
+      ;; => <Nothing>
 
       (monad+ [0 2 4] [1 2])
-      ;=> [1 2 3 4 5 6]
+      ;; => [1 2 3 4 5 6]
   "
   [n f]
   (let [val-syms (repeatedly n gensym)

    (mzero)))

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


  This is multiarity function that with arity pure/1
  it uses the dynamic scope to resolve the current
  context. With `pure/2`, you can force a specific context
  value.

  Example:

      (with-monad either/either-monad
        (pure 1)
      ;; => #<Right [1]>
  "
  ([v] (pure (get-current-context) v))
  ([ctx v] (p/pure ctx v)))

(defn return
  "This is a monad version of pure and it works
  identically to it."
  ([v] (return (get-current-context) v))
  ([ctx v] (p/mreturn ctx v)))

(defn bind
  "Given a value inside monadic context `mv` and any function,
  applies a function to value of mv.

      (bind (either/right 1) (fn [v]
                               (return (inc v))))
      ;; => #<Right [2]>

  For convenience, you may prefer use a `mlet` macro
  that add a beautiful, let like syntax for
  compose operations with `bind` function."
  [mv f]
  (cond
    (satisfies? p/MonadTrans *context*)
