### Clojure: Composing multiple threading macros for complex workflows Source: https://github.com/kumarshantanu/promenade/blob/master/doc/intro.md Demonstrates composing `maybe->`, `either->`, `either->>`, and `trial->` to build a complex processing chain. This example handles order processing, including cache misses, inventory checks, order cancellation, stock replenishment, and final fulfillment, while also managing potential exceptions. ```clojure (-> order-id fetch-order-details-from-cache (prom/maybe-> [(do (fetch-order-details-from-db))]) ; only error-handles Nothing. E.g. a cache miss (prom/either-> check-inventory) (prom/either->> [(cancel-order order-id) process-order]) ; Cancel order when Failure, or process valid values (prom/either-> [stock-replenish-init]) ; Only if the prior step result was a Failure (prom/either-> fulfil-order) ; Only if we still have a valid value (prom/maybe-> [(do (not-found-error))]) ; Handle the possibility that Nothing flowed through from the fetch (prom/trial-> [generate-error])) ; Handle any exceptions. Any above step could have returned a Thrown ``` -------------------------------- ### Initialize Promenade Dependency and Namespaces Source: https://context7.com/kumarshantanu/promenade/llms.txt Instructions for adding the library to a Clojure project and requiring the necessary namespaces for context operations. ```clojure ;; Add to project.clj dependencies [promenade "0.8.0"] ;; Require namespaces (require '[promenade.core :as prom] '[promenade.util :as prut]) ``` -------------------------------- ### Context Composition Source: https://context7.com/kumarshantanu/promenade/llms.txt Demonstrates how to compose different context types (Maybe, Either, Trial) within a single pipeline. Each bind variant passes unknown contexts through, allowing for complex error handling strategies. ```clojure (-> order-id fetch-order-details-from-cache (prom/maybe-> [(do (fetch-order-details-from-db order-id))]) (prom/either-> check-inventory) (prom/either->> [(cancel-order order-id) process-order]) (prom/trial-> [generate-error])) ``` -------------------------------- ### Clojure: Chaining operations with trial-> and trial->> Source: https://github.com/kumarshantanu/promenade/blob/master/doc/intro.md Illustrates chaining operations that may throw exceptions using `prom/trial-as->` and `prom/trial->>`. It shows how to handle potential exceptions during fetching and processing, including fallback mechanisms and error reporting. ```clojure (prom/trial-as-> id $ (! (http/fetch-by-key $)) ; fetch-by-key may throw [(fallback-fetch id $)] (! (process-item $)) ; process-item may throw [(error-report $)]) ;; or (let [r-fetch (prom/!wrap http/fetch-by-key) ; wrap functions that may throw process (prom/!wrap process-item)] (prom/trial->> id r-fetch [(fallback-fetch id)] process [error-report])) ``` -------------------------------- ### Create and Handle Failure Contexts Source: https://context7.com/kumarshantanu/promenade/llms.txt Demonstrates how to wrap values as failure contexts and handle ExceptionInfo objects to maintain clean error states. ```clojure (def order-failure (prom/fail {:error :invalid-order :order-id 12345})) (def generic-failure prom/failure) @(prom/fail {:reason "Item out of stock"}) (prom/ex-fail (throw (ex-info "Order failed" {:order-id 123}))) ``` -------------------------------- ### Trial Context Binding and Threading Source: https://context7.com/kumarshantanu/promenade/llms.txt Functions and macros for managing exception-throwing operations. The bind-trial function routes results or exceptions, while trial-> macros provide pipeline syntax for capturing and handling errors via the ! macro. ```clojure (prom/bind-trial (prom/! (/ 1 0)) identity) (prom/trial-> id (prom/! (fetch-from-api id)) [log-api-error] (prom/! (parse-response)) [(fn [ex] {:error (.getMessage ex)})]) (prom/trial-as-> order-id $ (prom/! (http/fetch-order $)) [(fallback-fetch-order $)] (prom/! (validate-order $)) [(log-validation-error $)] (create-confirmation $)) ``` -------------------------------- ### Clojure: Capturing exceptions with prom/! and !wrap Source: https://github.com/kumarshantanu/promenade/blob/master/doc/intro.md Shows how to use `prom/!` to wrap code that might throw exceptions, converting them into `Thrown` context values. Also demonstrates `!wrap` for creating functions that automatically return `Thrown` instead of throwing. ```clojure (defn get-from-db [id] (prom/! (let [v (jdbc/query ...)] v))) ;; or (def get-from-db (!wrap (fn [id] (prom/! (let [v (jdbc/query ...)] v))))) ``` -------------------------------- ### Manage Stackless Exceptions with se-info Source: https://context7.com/kumarshantanu/promenade/llms.txt Provides lightweight exceptions for flow control without the overhead of stack traces. Includes utilities for throwing, detecting, and wrapping functions to handle anticipated errors. ```clojure ;; Create and throw stackless exception (throw (prut/se-info "Order not found" {:order-id order-id})) ;; Detect stackless exceptions (prut/se-info? ex) ;; Use with promenade.core via !se-info macro (prut/!se-info (when (nil? order) (throw (prut/se-info "Order not found" {:id order-id}))) (process-order order)) ;; Wrap functions with !wrap-se-info (def safe-validate (prut/!wrap-se-info (fn [order] (when-not (valid? order) (throw (prut/se-info "Invalid order" (select-keys order [:id])))) order))) ;; Compatible with ex-data (ex-data (prut/se-info "Error" {:code 404})) ``` -------------------------------- ### Require Promenade namespaces Source: https://github.com/kumarshantanu/promenade/blob/master/doc/intro.md Initializes the library by requiring the core and utility namespaces. ```clojure (require '[promenade.core :as prom] '[promenade.util :as prut]) ``` -------------------------------- ### Stackless Exception Info in Clojure Source: https://github.com/kumarshantanu/promenade/blob/master/doc/intro.md Promenade provides `se-info` for creating stackless exception information, offering a faster alternative to Clojure's `ex-info` when stack traces are not needed. It is compatible with `ex-data` and `ex-message` and is a subclass of `ExceptionInfo`. ```clojure ;; throwing (throw (prut/se-info "Order fetching failed" {:order-id order-id})) ;; catching (catch promenade.util.StacklessExceptionInfo ex ...) ;; detecting (prut/se-info? ex) ``` -------------------------------- ### Implement context-aware threading with either-> Source: https://github.com/kumarshantanu/promenade/blob/master/doc/intro.md Demonstrates the use of prom/either-> to thread values through a sequence of operations while providing recovery handlers via vectors. This approach maintains error context and allows for conditional execution based on success or failure states. ```clojure (prom/either-> id lookup [(attempt-alternate-lookup id)] transform write-to-db [(log-error other-arg)]) ``` -------------------------------- ### Creating Entities with defentity in Clojure Source: https://github.com/kumarshantanu/promenade/blob/master/doc/intro.md The `prut/defentity` macro simplifies the creation of records (entities) with or without explicit fields. It automatically generates a predicate function to test instances of the created entity, making entity identification more straightforward. ```clojure ;; --- records with implicit single field (called 'value') ;; (prut/defentity ProductCode) ; similar to (defrecord ProductCode [value]) (def prod-code (-> ProductCode "JCF-69WQ45R")) (:value prod-code) (ProductCode? prod-code) ; defentity creates a predicate to test instances ;; --- records with explicit fields ;; (prut/defentity Location [latitude longitude]) ; syntax similar to defrecord (Location? (->Location 8.6705 115.2126)) ; defentity created predicate ``` -------------------------------- ### Reducing functions with Promenade Source: https://github.com/kumarshantanu/promenade/blob/master/doc/intro.md Demonstrates using Promenade context results within standard reduce or transducer operations. ```clojure (reduce (prom/refn [a x] (prom/either->> x process-valid-item (conj a))) [] found-items) (defn process-all [a x] (prom/either->> x process-valid-item (conj a))) (reduce (rewrap process-all) [] found-items) ``` -------------------------------- ### Monadic binding with mlet Source: https://github.com/kumarshantanu/promenade/blob/master/doc/intro.md Demonstrates the mlet macro for non-linear pipelines, allowing for implicit or explicit matching of monadic results. ```clojure (prom/mlet [order (find-order-details order-id) stock (check-inventory (:items order)) f-ord (process-order order stock)] (fulfil-order f-ord)) (prom/mlet [cached (prom/mnothing (find-cached-order order-id) :absent) order (find-order-details-from-db order-id)] (update-cache order-id order) order) ``` -------------------------------- ### Clojure: Thread-first data fetching with maybe-> Source: https://github.com/kumarshantanu/promenade/blob/master/doc/intro.md Demonstrates using `prom/maybe->` for a thread-first data fetching sequence. It attempts to fetch data from a cache, falling back to a database if not found, and then decompresses the data if successfully retrieved. Handles `prom/nothing` results. ```clojure (prom/maybe-> data-id ; begin with data-id fetch-from-cache ; attemp to fetch the data from cache, which may return a value or prom/nothing [(do (fetch-from-db data-id)] ; if not found in cache then fetch from DB, which may return a value or prom/nothing decompress) ; if data was fetched then decompress it before returning to the caller ``` -------------------------------- ### Maybe Context Threading Macros Source: https://context7.com/kumarshantanu/promenade/llms.txt Thread-first, thread-last, and thread-anywhere macros for handling optional values. These macros use bind-maybe to route values through pipelines, allowing for recovery from 'Nothing' states using vector-based handlers. ```clojure (prom/maybe-> data-id fetch-from-cache [(do (fetch-from-db data-id))] decompress) (prom/maybe->> user-id (find-user db) [(log-user-not-found)] (get :email) [(do default-email)] (send-notification message)) (prom/maybe-as-> product-id $ (find-product $ catalog) [(do {:id $ :status :not-found})] (calculate-price $ discount-rate) (format-response $ :json)) ``` -------------------------------- ### Early Termination with reduced in Clojure Source: https://context7.com/kumarshantanu/promenade/llms.txt Demonstrates using clojure.core/reduced to short-circuit processing chains in Promenade pipelines. Useful for handling validation failures or conditional early returns. ```clojure ;; Bail out early on validation failure (prom/either-> order-id validate-order-id [(-> validation-error reduced)] ; Terminate chain on invalid ID fetch-order-details process-order [handle-processing-failure]) ;; Early return on success condition (prom/either-> user-id check-premium-status [do] ; Recover from non-premium (fn [user] (if (:vip user) (reduced {:discount 0.5}) ; VIP gets 50% - skip rest user)) apply-standard-discounts calculate-final-price) ``` -------------------------------- ### Either Threading Macros in Clojure Source: https://context7.com/kumarshantanu/promenade/llms.txt Provides thread-first, thread-last, and thread-as macros for Either contexts. These macros allow for clean pipeline construction with inline recovery expressions using vector syntax. ```clojure ;; Thread-first example (prom/either-> :foo {:foo 1 :bar 2} inc (* 3)) ;; Thread-last example (prom/either->> :foo {:foo 1 :bar 2} (vector 2) first) ;; Thread-as example (prom/either-as-> :foo $ ({:foo 1 :bar 2} $) (vector $ 2) (first $)) ``` -------------------------------- ### Clojure: Chaining `bind-maybe` with Threading Macros Source: https://github.com/kumarshantanu/promenade/blob/master/doc/intro.md Illustrates chaining `bind-maybe` operations using threading macros like `maybe->>` for managing values that might be absent. These macros simplify the process of handling `Nothing` contexts within a sequence of operations. ```clojure (prom/maybe->> order-id fetch-order-details check-inventory [(cancel-order order-id) process-order] [stock-replenish-init] fulfil-order) ``` -------------------------------- ### Capture Exceptions with Thrown Context Source: https://context7.com/kumarshantanu/promenade/llms.txt Wraps exceptions into a context to prevent stack unwinding and provides tools like the ! macro and !wrap for safe function execution. ```clojure (prom/thrown (Exception. "Database connection failed")) (prom/! (/ 10 0)) @(prom/! (throw (Exception. "test"))) (def safe-parse-int (prom/!wrap (fn [s] (Integer/parseInt s)))) (safe-parse-int "123") (safe-parse-int "invalid") ``` -------------------------------- ### Define Domain Entities with defentity Source: https://context7.com/kumarshantanu/promenade/llms.txt Creates record types with automatic predicate functions. Supports both single-field entities and multi-field structures for domain modeling. ```clojure ;; Single-field entity (prut/defentity ProductCode) (def code (->ProductCode "ABC-123")) (ProductCode? code) ;; Multi-field entity (prut/defentity Location [latitude longitude]) (def loc (->Location 37.7749 -122.4194)) (Location? loc) ``` -------------------------------- ### Early termination in threading macros Source: https://github.com/kumarshantanu/promenade/blob/master/doc/intro.md Shows how to terminate a chain of expressions early by wrapping a result in clojure.core/reduced. ```clojure (prom/either-> order-id validate-order-id [(-> validation-error reduced)] process-order [handle-order-processing-failure]) ``` -------------------------------- ### Verify Context Types with Predicates Source: https://context7.com/kumarshantanu/promenade/llms.txt Functions to test values against specific context types (Failure, Nothing, Thrown, or Context-free). These are essential for conditional logic within processing pipelines. ```clojure ;; Test for failure context (prom/failure? (prom/fail :error)) ; => true (prom/failure? prom/failure) ; => true (prom/failure? :regular-value) ; => false ;; Test for nothing context (prom/nothing? prom/nothing) ; => true (prom/nothing? (prom/void :any-value)) ; => true (prom/nothing? :regular-value) ; => false ;; Test for thrown context (prom/thrown? (prom/thrown (Exception. "error"))) ; => true (prom/thrown? (prom/! (throw (Exception. "test")))) ; => true (prom/thrown? :regular-value) ; => false ;; Test for any context type (prom/context? (prom/fail :error)) ; => true (prom/context? prom/nothing) ; => true (prom/context? :regular-value) ; => false ;; Test for context-free (regular) values (prom/free? :regular-value) ; => true (prom/free? (prom/fail :error)) ; => false ``` -------------------------------- ### Intermixing bind functions in Promenade Source: https://github.com/kumarshantanu/promenade/blob/master/doc/intro.md Demonstrates the use of 3-element vector forms in threading macros to intermix bind functions for error handling and conditional logic. ```clojure (prom/either-> order-id fetch-order-details-from-cache [prom/bind-maybe (do (fetch-order-details-from-db order-id)) do] check-inventory [(cancel-order order-id) process-order] [stock-replenish-init] fulfil-order [prom/bind-maybe (do (not-found-error)) do] [prom/bind-trial generate-error do]) ``` -------------------------------- ### Reducing Functions with refn and rewrap Source: https://context7.com/kumarshantanu/promenade/llms.txt Creates reducing functions that automatically terminate upon encountering specific monadic contexts, compatible with standard reduce and transducers. ```clojure ;; refn creates a reducing function that bails on context (reduce (prom/refn [acc x] (if (zero? x) prom/failure ; Return failure, terminates reduce (* acc x))) 1 [1 2 3 4 5]) ; => 120 (reduce (prom/refn [acc x] (if (zero? x) prom/failure (* acc x))) 1 [1 2 0 4 5]) ; => Failure (terminated early) ;; rewrap wraps existing reducing function (defn process-item [acc x] (prom/either->> x validate-item (conj acc))) (reduce (prom/rewrap process-item) [] items) ;; Custom context predicate (reduce (prom/refn prom/nothing? [acc x] (if (nil? x) prom/nothing ; Terminate on nil (conj acc x))) [] [1 2 nil 4 5]) ; => Nothing (terminated at nil) ``` -------------------------------- ### Bind Maybe Context in Clojure Source: https://context7.com/kumarshantanu/promenade/llms.txt The bind-maybe function manages Maybe contexts, routing present values through 'just' handlers and Nothing values through 'nothing' handlers. Useful for cache lookups and optional value pipelines. ```clojure (prom/bind-maybe :foo identity) (prom/bind-maybe prom/nothing identity) (-> :foo (prom/bind-maybe (constantly prom/nothing)) (prom/bind-maybe (fn [_] :not-found) (fn [v] [:found v]))) (-> user-id (prom/bind-maybe find-in-cache) (prom/bind-maybe (fn [_] (fetch-from-db user-id)) identity)) ``` -------------------------------- ### Clojure: Chaining `bind-either` with Threading Macros Source: https://github.com/kumarshantanu/promenade/blob/master/doc/intro.md Demonstrates chaining `bind-either` operations using threading macros for cleaner code. The `either->>` macro is a thread-last variant that handles success and failure cases, with failure handlers specified in vector form. ```clojure (-> order-id (prom/bind-either (fn [v] (fetch-order-details v))) (prom/bind-either (fn [v] (cancel-order v order-id)) (fn [v] (process-order v))) ...) ``` ```clojure (prom/either->> order-id ; begin with ID of the placed order fetch-order-details ; fetch order details (may succeed or fail) check-inventory ; check inventory levels of the items in order (may succeed or fail) [(cancel-order order-id) process-order] ; on failure cancel the order, else process the order [stock-replenish-init] ; if low stock led to cancelled order then initiate stock replenishment fulfil-order) ; if there were no failure then initiate order fulfilment ``` -------------------------------- ### Conditional Monadic Bindings with if-mlet and when-mlet Source: https://context7.com/kumarshantanu/promenade/llms.txt Provides conditional logic for monadic bindings, allowing for else branches or returning nil when bindings fail. ```clojure ;; if-mlet with else branch (prom/if-mlet [order (find-order-details order-id) stock (check-inventory (:items order)) f-ord (process-order order stock)] (fulfil-order f-ord) ; Then: all matched (prom/fail {:module :order-processing ; Else: something didn't match :order-id order-id})) ;; when-mlet returns nil on non-match (prom/when-mlet [order (find-order-details order-id) stock (check-inventory (:items order)) f-ord (process-order order stock)] (println "Fulfilling order:" order-id) (fulfil-order f-ord)) ; => nil if any binding fails ``` -------------------------------- ### Clojure: `bind-either` for Explicit Failure Handling Source: https://github.com/kumarshantanu/promenade/blob/master/doc/intro.md The `bind-either` function handles success and failure results. It takes a monadic value and one or two functions. If the value is a success, it applies the success function. If it's a failure, it applies the failure function. Other context types are passed through. ```clojure (defn bind-either ([mval success-f] (if (context? mval) mval (success-f mval))) ([mval failure-f success-f] (cond (failure? mval) (failure-f (deref mval)) (context? mval) mval :otherwise (success-f mval)))) ``` -------------------------------- ### Define context binding logic Source: https://github.com/kumarshantanu/promenade/blob/master/doc/intro.md Shows the structural pattern for binding handlers to specific context types. The logic checks if the input is a context and applies either a failure handler or a success function accordingly. ```clojure (defn bind-CONTEXT-TYPE ([mval success-f] (if (context? mval) mval (success-f mval))) ([mval failure-f success-f] (cond (CONTEXT-TEST mval) (failure-f (deref mval)) (context? mval) mval :otherwise (success-f mval)))) ``` -------------------------------- ### Monadic Let Binding with mlet Source: https://context7.com/kumarshantanu/promenade/llms.txt Utilizes the mlet macro to perform monadic let bindings. It evaluates bodies only when context values match, returning immediately on failure or nothing. ```clojure ;; Basic mlet - binds on success, aborts on failure (prom/mlet [order (find-order-details order-id) ; Binds on value, Nothing aborts stock (check-inventory (:items order)) ; Binds on success, Failure aborts f-ord (process-order order stock)] (fulfil-order f-ord)) ;; Explicit matcher with mfailure (prom/mlet [cached (prom/mnothing (find-cached-order order-id) :absent) ; Continue on Nothing order (find-order-details-from-db order-id)] ; Abort on Failure (update-cache order-id order) order) ;; Multiple matches (prom/mlet [a (prom/mfailure (prom/fail :foo)) ; Match failure, bind :foo b (prom/mnothing prom/nothing :bar)] ; Match nothing, bind :bar [a b]) ; => [:foo :bar] ``` -------------------------------- ### Bind Either Context in Clojure Source: https://context7.com/kumarshantanu/promenade/llms.txt The bind-either function routes values through success or failure handlers. It supports two-arity for simple success mapping and three-arity for explicit failure and success handling. ```clojure (prom/bind-either :foo identity) (prom/bind-either (prom/fail :x) identity) (-> :foo (prom/bind-either (fn [v] (prom/fail v))) (prom/bind-either (fn [fail-data] {:recovered fail-data}) (fn [v] [:success v]))) (-> order-id (prom/bind-either fetch-order) (prom/bind-either (fn [err] (log-error err)) (fn [order] (process-order order)))) ``` -------------------------------- ### Conditional Pipelines with branch Source: https://context7.com/kumarshantanu/promenade/llms.txt Creates conditional pipelines that only process values matching a specific predicate, useful for filtering or transforming data within sequences. ```clojure ;; Only process context-free values (def process-valid-item (prom/branch prom/free? process-item)) (map process-valid-item found-items) ; Processes only non-context values ;; Chain multiple branches (def complex-processor (-> identity (prom/branch number? inc) (prom/branch string? clojure.string/upper-case) (prom/branch keyword? name))) (complex-processor 10) ; => 11 (complex-processor "hello") ; => "HELLO" (complex-processor :foo) ; => "foo" ``` -------------------------------- ### Represent Absence of Data with Nothing Context Source: https://context7.com/kumarshantanu/promenade/llms.txt Uses the nothing constant and void function to represent missing values, commonly used for cache misses or optional lookups. ```clojure prom/nothing (prom/void :any-value) (prom/void) (defn find-in-cache [id] (if-let [item (get @cache id)] item prom/nothing)) ``` -------------------------------- ### Implement Typed Failures with defailure Source: https://context7.com/kumarshantanu/promenade/llms.txt Defines custom failure types that act as Failure contexts. These are useful for domain-specific error handling within pipeline operations. ```clojure ;; Define a custom failure type (prut/defailure OrderFetchFailure [order-id reason]) ;; Create instance (def fetch-error (->OrderFetchFailure "ORD-123" :not-found)) ;; Use in pipelines (prom/either-> order-id fetch-order [(fn [_] (->OrderFetchFailure order-id :fetch-failed))] process-order [(fn [fail] (when (OrderFetchFailure? fail) (notify-support (:order-id fail) (:reason fail))))]) ``` -------------------------------- ### Conditional Branching with cond-mlet Source: https://context7.com/kumarshantanu/promenade/llms.txt Matches multiple combinations of monadic contexts and evaluates the first branch that succeeds. ```clojure (let [job (post-job job-details) sch (schedule-job job)] (prom/cond-mlet [j job s sch] {:status :success ; Both succeeded :job-id (:job-id sch)} [j job s (prom/mfailure sch)] {:status :partial-success ; Job posted, schedule failed :job-id (:job-id job)} :else (prom/fail :failure))) ; Both failed ``` -------------------------------- ### Optional Execution with when-mlet in Clojure Source: https://github.com/kumarshantanu/promenade/blob/master/doc/intro.md The `when-mlet` macro executes a body of code only if all bound expressions succeed. If any binding fails, the macro aborts and returns nil. It's useful for sequential operations where subsequent steps depend on the success of prior ones. ```clojure (prom/when-mlet [order (find-order-details order-id) stock (check-inventory (:items order)) f-ord (process-order order stock)] (println "Fulfilling order:" order-id) (fulfil-order f-ord)) ``` -------------------------------- ### Multi-Condition Matching with cond-mlet in Clojure Source: https://github.com/kumarshantanu/promenade/blob/master/doc/intro.md The `cond-mlet` macro allows matching multiple combinations of results from bound expressions. It evaluates clauses sequentially and executes the body of the first clause whose conditions are met. An `:else` clause can be provided for a default case. ```clojure (let [job (post-job job-details) sch (schedule-job job)] (prom/cond-mlet [j job s sch] {:status :sucess :job-id (:job-id sch)} [j job s (prom/mfailure sch)] {:status :partial-success} :else (prom/fail :failure))) ``` -------------------------------- ### Clojure: `bind-maybe` for Presence or Absence of a Value Source: https://github.com/kumarshantanu/promenade/blob/master/doc/intro.md The `bind-maybe` function handles monadic values that may represent the presence of a value or its absence (`prom/nothing`). It follows a similar pattern to `bind-either`, applying a `just-f` for regular values and a `nothing-f` for `Nothing` contexts. ```clojure (defn bind-maybe ([mval just-f] (if (context? mval) mval (just-f mval))) ([mval nothing-f just-f] (cond (nothing? mval) (nothing-f) (context? mval) mval :otherwise (just-f mval)))) ``` -------------------------------- ### Conditional Execution with if-mlet in Clojure Source: https://github.com/kumarshantanu/promenade/blob/master/doc/intro.md The `if-mlet` macro provides conditional execution based on the success of bound expressions. It allows specifying a success branch and an else branch, returning the result of the executed branch. Failures in bound expressions lead to the else branch. ```clojure (prom/if-mlet [order (find-order-details order-id) stock (check-inventory (:items order)) f-ord (process-order order stock)] (fulfil-order f-ord) (prom/fail {:module :order-processing :order-id order-id})) ``` -------------------------------- ### Defining Custom Failures with defailure in Clojure Source: https://github.com/kumarshantanu/promenade/blob/master/doc/intro.md The `defailure` macro allows for the creation of custom failure entities, similar to `defrecord`, but instances are inherently failures. This approach avoids the overhead of wrapping data in a generic `Failure` object and provides identity to failures. ```clojure (defailure OrderFetchFailure [order-id]) ; like an ordinary defrecord (OrderFetchFailure? failure) ; defailure created predicate ``` -------------------------------- ### Branching sequence operations Source: https://github.com/kumarshantanu/promenade/blob/master/doc/intro.md Uses the branch function to filter or process items in a sequence based on whether they are context values or ordinary values. ```clojure (def process-valid-item (prom/branch prom/free? process-item)) (map process-valid-item found-items) ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.