Skip to content

Instantly share code, notes, and snippets.

@piotr-yuxuan
Last active May 5, 2020 11:58
Show Gist options
  • Save piotr-yuxuan/c916f4daef652bc8347bba2a703ad4fd to your computer and use it in GitHub Desktop.
Save piotr-yuxuan/c916f4daef652bc8347bba2a703ad4fd to your computer and use it in GitHub Desktop.
Exploration of a few funcool.cats control flow structures
(ns meew
(:require [cats.core :refer [mlet do-let extract return]]
[cats.monad.either :refer [branch-left left right]]))
(defn http-get! [{:keys [success-rate some-arg]}]
(-> (repeat success-rate {:status :ok, :result (* some-arg (rand-int 10))})
(conj {:status :ko, :error "computation error!"})
rand-nth))
;; ✅ stop at the first error
;; ❌ custom error handling
;; ❌ return the last successful computation
;; ❌ reuse previous computations
;; ❌ return a aggregated reduction in case of all successful computation
;; ✅ keep reading complexity low
(and
(= :ok (:status (http-get! {:success-rate 8 :some-arg 1})))
(= :ok (:status (http-get! {:success-rate 4 :some-arg 2})))
(= :ok (:status (http-get! {:success-rate 2 :some-arg 3}))))
;; ✅ stop at the first error
;; ❌ custom error handling
;; ❌ return the last successful computation
;; ❌ reuse previous computations
;; ❌ return a aggregated reduction in case of all successful computation
;; 🟠 keep reading complexity low
(condp (fn [{:keys [status]} ko] (println :condp-test :status status) (= status ko)) :ko
(http-get! {:success-rate 10 :some-arg 1}) "first computation failed" ;; doesn't depend on the error
(http-get! {:success-rate 10 :some-arg 2}) "second computation failed"
(http-get! {:success-rate 10 :some-arg 3}) "third computation failed"
"all computations succeeded")
;; ✅ stop at the first error
;; ❌ custom error handling
;; ✅ return the last successful computation
;; ❌ reuse previous computations
;; ❌ return a aggregated reduction in case of all successful computation
;; ❌ keep reading complexity low
(condp (fn [{:keys [status]} ko] (println :condp-test :status status) (= status ko)) :ko
(http-get! {:success-rate 10 :some-arg 1}) "first computation failed"
(http-get! {:success-rate 10 :some-arg 2}) "second computation failed"
(http-get! {:success-rate 10 :some-arg 3}))
;; ✅ stop at the first error
;; ✅ custom error handling
;; ❌ return the last successful computation
;; ❌ reuse previous computations
;; ❌ return a aggregated reduction in case of all successful computation
;; ❌ keep reading complexity low
(condp (fn [{:keys [status] :as response} ko] (when (= status ko) response)) :ko
(http-get! {:success-rate 10 :some-arg 1})
:>> (fn [{:keys [error]}] (str "computation 1 failed, error is: " error))
(http-get! {:success-rate 10 :some-arg 2})
:>> (fn [{:keys [error]}] (str "computation 2 failed, error is: " error))
(http-get! {:success-rate 10 :some-arg 3})
:>> (fn [{:keys [error]}] (str "computation 3 failed, error is: " error))
"all computations succeeded, but we can't access results")
;; ✅ stop at the first error
;; ✅ custom error handling
;; ✅ return the last successful computation
;; ✅ reuse previous computations
;; ✅ return a aggregated reduction in case of all successful computation
;; ❌ keep reading complexity low
(let [{:keys [status] :as first-computation} (http-get! {:success-rate 10 :some-arg 1})]
(if (= :ok status)
(let [{:keys [status] :as second-computation} (http-get! {:success-rate 10 :some-arg 2})]
(if (= :ok status)
(let [{:keys [status] :as third-computation} (http-get! {:success-rate 10 :some-arg 3})]
(if (= :ok status)
{:transaction-response (reduce + (map :result [first-computation second-computation third-computation]))}
third-computation))
second-computation))
first-computation))
(defn http-get-either! [query]
(let [{:keys [status] :as response} (http-get! query)]
(if (= :ok status)
(right response)
(left {:status :ko, :error "computation error!"}))))
;; ✅ stop at the first error
;; ❌ custom error handling
;; ✅ return the last successful computation
;; ❌ reuse previous computations
;; ❌ return a aggregated reduction in case of all successful computation
;; ✅ keep reading complexity low
(extract
(do-let
(http-get-either! {:success-rate 10 :some-arg 1})
(http-get-either! {:success-rate 10 :some-arg 2})
(http-get-either! {:success-rate 10 :some-arg 3})))
;; ✅ stop at the first error
;; ❌ custom error handling
;; ✅ return the last successful computation
;; ❌ reuse previous computations
;; ❌ return a aggregated reduction in case of all successful computation
;; ✅ keep reading complexity low
(extract
(do-let
(http-get-either! {:success-rate 10 :some-arg 1})
(http-get-either! {:success-rate 10 :some-arg 2})
(http-get-either! {:success-rate 10 :some-arg 3})
(right {:message "all computations succeeded, but we can't access results"})))
;; ✅ stop at the first error
;; ❌ custom error handling
;; ✅ return the last successful computation
;; ✅ reuse previous computations
;; ✅ return a aggregated reduction in case of all successful computation
;; ✅ keep reading complexity low
(extract
(mlet [first-computation (http-get-either! {:success-rate 8 :some-arg 1})
second-computation (http-get-either! {:success-rate 4 :some-arg 2})
third-computation (http-get-either! {:success-rate 2 :some-arg 3})]
(return {:transaction-response (reduce + (map :result [first-computation second-computation third-computation]))})))
;; ✅ stop at the first error
;; 🟠 custom error handling
;; ✅ return the last successful computation
;; ✅ reuse previous computations
;; ❌ return a aggregated reduction in case of all successful computation
;; ✅ keep reading complexity low
(extract
(branch-left
(do-let
(http-get-either! {:success-rate 10 :some-arg 1})
(http-get-either! {:success-rate 10 :some-arg 2})
(http-get-either! {:success-rate 10 :some-arg 3}))
(fn [response]
(left {:error "some computation failed"
:failed response}))))
;; ✅ stop at the first error
;; ✅ custom error handling
;; ✅ return the last successful computation
;; ✅ reuse previous computations
;; ❌ return a aggregated reduction in case of all successful computation
;; ✅ keep reading complexity low
(extract
(do-let
(branch-left (http-get-either! {:success-rate 10 :some-arg 1}) (fn [_response] (left {:error "first computation failed"})))
(branch-left (http-get-either! {:success-rate 10 :some-arg 2}) (fn [_response] (left {:error "second computation failed"})))
(branch-left (http-get-either! {:success-rate 10 :some-arg 3}) (fn [_response] (left {:error "third computation failed"})))))
;; ✅ stop at the first error
;; ✅ custom error handling
;; ✅ return the last successful computation
;; ✅ reuse previous computations
;; ✅ return a aggregated reduction in case of all successful computation
;; ✅ keep reading complexity low
(extract
(mlet [first-computation (branch-left (http-get-either! {:success-rate 10 :some-arg 1}) (fn [_response] (left {:error "first computation failed"})))
second-computation (branch-left (http-get-either! {:success-rate 10 :some-arg 2}) (fn [_response] (left {:error "second computation failed"})))
third-computation (branch-left (http-get-either! {:success-rate 10 :some-arg 3}) (fn [_response] (left {:error "third computation failed"})))]
(return {:transaction-response (reduce + (map :result [first-computation second-computation third-computation]))})))
;; see real-life examples
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment