From 872e89f97871d44a6440910690a121c08666d20e Mon Sep 17 00:00:00 2001 From: Tiago Vidal Date: Tue, 10 Oct 2023 12:06:48 -0300 Subject: [PATCH 1/7] add applicative manifold engine context --- src/nodely/engine/applicative/manifold.clj | 40 ++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 src/nodely/engine/applicative/manifold.clj diff --git a/src/nodely/engine/applicative/manifold.clj b/src/nodely/engine/applicative/manifold.clj new file mode 100644 index 0000000..0605e18 --- /dev/null +++ b/src/nodely/engine/applicative/manifold.clj @@ -0,0 +1,40 @@ +(ns nodely.engine.applicative.manifold + (:require [cats.protocols :as mp] + [manifold.deferred :as deferred])) + +(declare context) + +(extend-type manifold.deferred.Deferred + mp/Contextual + (-get-context [_] context) + + mp/Extract + (-extract [it] + (try (deref it) + (catch java.util.concurrent.ExecutionException e + (throw (.getCause e)))))) + +(def ^:no-doc context + (reify + mp/Context + mp/Functor + (-fmap [_ f mv] + (deferred/chain mv f)) + + mp/Monad ;; goood + (-mreturn [_ v] + (deferred/success-deferred v)) + + ;; Channel a -> (a -> Channel b) -> Channel b + (-mbind [_ mv f] + (deferred/chain mv (fn [v] + (f v)))) + + mp/Applicative + (-pure [_ v] + (deferred/success-deferred v)) + + (-fapply [_ pf pv] + (deferred/chain (deferred/zip' pf pv) + (fn [[f v]] + (f v)))))) From 21d7b55af7780f2a6dfe99e2875663596cdcac43 Mon Sep 17 00:00:00 2001 From: joaopluigi Date: Tue, 24 Oct 2023 12:09:49 -0300 Subject: [PATCH 2/7] add tests --- src/nodely/engine/applicative/manifold.clj | 2 +- test/nodely/engine/applicative_test.clj | 26 ++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/nodely/engine/applicative/manifold.clj b/src/nodely/engine/applicative/manifold.clj index 0605e18..6d94c69 100644 --- a/src/nodely/engine/applicative/manifold.clj +++ b/src/nodely/engine/applicative/manifold.clj @@ -4,7 +4,7 @@ (declare context) -(extend-type manifold.deferred.Deferred +(extend-type manifold.deferred.SuccessDeferred mp/Contextual (-get-context [_] context) diff --git a/test/nodely/engine/applicative_test.clj b/test/nodely/engine/applicative_test.clj index 1b7d5ee..62f281d 100644 --- a/test/nodely/engine/applicative_test.clj +++ b/test/nodely/engine/applicative_test.clj @@ -8,6 +8,7 @@ [nodely.data :as data] [nodely.engine.applicative :as applicative] [nodely.engine.applicative.core-async :as core-async] + [nodely.engine.applicative.manifold :as manifold] [nodely.engine.applicative.synchronous :as synchronous] [nodely.engine.core :as core] [nodely.engine.core-async.core :as nodely.async] @@ -183,3 +184,28 @@ (testing "channel-leaf" (is (= 7 (applicative/eval-key env+channel-leaf :c {::applicative/context core-async/context})))))) +(deftest manifold-applicative-test + (let [simple-env {:a (>value 2) + :b (>value 1) + :c (>leaf (+ ?a ?b))} + env-with-failing-schema {:a (>value 2) + :b (>value 1) + :c (yielding-schema (>leaf (+ ?a ?b)) s/Bool)}] + (testing "it should not fail" + (is (match? 3 (applicative/eval-key simple-env :c {::applicative/context manifold/context})))) + +; expected: (match? 3 (applicative/eval-key simple-env :c #:nodely.engine.applicative{:context manifold/context})) +; actual: java.lang.IllegalArgumentException: No implementation of method: :-extract of protocol: #'cats.protocols/Extract found for class: manifold.deferred.SuccessDeferred + + (testing "more complicated example" + (is (match? 4 (applicative/eval-key tricky-example :z {::applicative/context manifold/context})))) + + #_(testing "returns ex-info when schema is selected as fvalidate, and schema fn validation is enabled" + (is (thrown-match? clojure.lang.ExceptionInfo + {:type :schema.core/error + :schema java.lang.Boolean + :value 3} + (ex-data + (s/with-fn-validation + (applicative/eval-key env-with-failing-schema :c {::applicative/fvalidate schema/fvalidate + ::applicative/context manifold/context})))))))) From 20e6ae11dc7c1f7526e24eab8d38369dd6d7679a Mon Sep 17 00:00:00 2001 From: Tiago Vidal Date: Tue, 31 Oct 2023 11:30:36 -0300 Subject: [PATCH 3/7] add unit tests for error deferred --- src/nodely/engine/applicative/manifold.clj | 12 ++++++++++-- test/nodely/engine/applicative_test.clj | 21 +++++++++------------ 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/nodely/engine/applicative/manifold.clj b/src/nodely/engine/applicative/manifold.clj index 6d94c69..16a4d64 100644 --- a/src/nodely/engine/applicative/manifold.clj +++ b/src/nodely/engine/applicative/manifold.clj @@ -1,6 +1,7 @@ (ns nodely.engine.applicative.manifold - (:require [cats.protocols :as mp] - [manifold.deferred :as deferred])) + (:require + [cats.protocols :as mp] + [manifold.deferred :as deferred])) (declare context) @@ -14,6 +15,13 @@ (catch java.util.concurrent.ExecutionException e (throw (.getCause e)))))) +(extend-type manifold.deferred.ErrorDeferred + mp/Extract + (-extract [it] + (try (deref it) + (catch java.util.concurrent.ExecutionException e + (throw (.getCause e)))))) + (def ^:no-doc context (reify mp/Context diff --git a/test/nodely/engine/applicative_test.clj b/test/nodely/engine/applicative_test.clj index 62f281d..dff9f15 100644 --- a/test/nodely/engine/applicative_test.clj +++ b/test/nodely/engine/applicative_test.clj @@ -194,18 +194,15 @@ (testing "it should not fail" (is (match? 3 (applicative/eval-key simple-env :c {::applicative/context manifold/context})))) -; expected: (match? 3 (applicative/eval-key simple-env :c #:nodely.engine.applicative{:context manifold/context})) -; actual: java.lang.IllegalArgumentException: No implementation of method: :-extract of protocol: #'cats.protocols/Extract found for class: manifold.deferred.SuccessDeferred - (testing "more complicated example" (is (match? 4 (applicative/eval-key tricky-example :z {::applicative/context manifold/context})))) - #_(testing "returns ex-info when schema is selected as fvalidate, and schema fn validation is enabled" - (is (thrown-match? clojure.lang.ExceptionInfo - {:type :schema.core/error - :schema java.lang.Boolean - :value 3} - (ex-data - (s/with-fn-validation - (applicative/eval-key env-with-failing-schema :c {::applicative/fvalidate schema/fvalidate - ::applicative/context manifold/context})))))))) + (testing "returns ex-info when schema is selected as fvalidate, and schema fn validation is enabled" + (is (thrown-match? clojure.lang.ExceptionInfo + {:type :schema.core/error + :schema java.lang.Boolean + :value 3} + (ex-data + (s/with-fn-validation + (applicative/eval-key env-with-failing-schema :c {::applicative/fvalidate schema/fvalidate + ::applicative/context manifold/context})))))))) From 70fcba89c5ebbac7c8d22102bd35af7751e98047 Mon Sep 17 00:00:00 2001 From: Tiago Vidal Date: Tue, 31 Oct 2023 11:45:31 -0300 Subject: [PATCH 4/7] lint --- src/nodely/engine/applicative/manifold.clj | 3 +-- test/nodely/engine/applicative_test.clj | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/nodely/engine/applicative/manifold.clj b/src/nodely/engine/applicative/manifold.clj index 16a4d64..3ff3dfb 100644 --- a/src/nodely/engine/applicative/manifold.clj +++ b/src/nodely/engine/applicative/manifold.clj @@ -29,11 +29,10 @@ (-fmap [_ f mv] (deferred/chain mv f)) - mp/Monad ;; goood + mp/Monad (-mreturn [_ v] (deferred/success-deferred v)) - ;; Channel a -> (a -> Channel b) -> Channel b (-mbind [_ mv f] (deferred/chain mv (fn [v] (f v)))) diff --git a/test/nodely/engine/applicative_test.clj b/test/nodely/engine/applicative_test.clj index dff9f15..8bb5ab6 100644 --- a/test/nodely/engine/applicative_test.clj +++ b/test/nodely/engine/applicative_test.clj @@ -205,4 +205,4 @@ (ex-data (s/with-fn-validation (applicative/eval-key env-with-failing-schema :c {::applicative/fvalidate schema/fvalidate - ::applicative/context manifold/context})))))))) + ::applicative/context manifold/context})))))))) From 631c1a5b9a593bfe25ffdd943784fcb394e27b85 Mon Sep 17 00:00:00 2001 From: joaopluigi Date: Tue, 14 Nov 2023 11:08:25 -0300 Subject: [PATCH 5/7] add manifold applicative engine test --- test/nodely/engine/applicative_test.clj | 65 +++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/test/nodely/engine/applicative_test.clj b/test/nodely/engine/applicative_test.clj index 8bb5ab6..6c53d0b 100644 --- a/test/nodely/engine/applicative_test.clj +++ b/test/nodely/engine/applicative_test.clj @@ -29,6 +29,15 @@ :b ?b :c ?c})}) +(def test-env+delay-async {:a (>leaf (+ 1 2)) + :b (>leaf (do (Thread/sleep 1000) + (* ?a 2))) + :c (>leaf (do (Thread/sleep 1000) + (* ?a 3))) + :d (>leaf {:a ?a + :b ?b + :c ?c})}) + (def tricky-example {:x (data/value 1) :y (data/value 2) :a (data/value 3) @@ -206,3 +215,59 @@ (s/with-fn-validation (applicative/eval-key env-with-failing-schema :c {::applicative/fvalidate schema/fvalidate ::applicative/context manifold/context})))))))) + +(deftest manifold-eval-key-test + (testing "eval promise" + (is (match? 3 (applicative/eval-key test-env :c {::applicative/context core-async/context})))) + (testing "async works" + (let [[time-ns result] (criterium/time-body (applicative/eval-key test-env+delay-async + :d + {::applicative/context manifold/context}))] + (is (match? {:a 3 :b 6 :c 9} result)) + (is (match? (matchers/within-delta 100000000 1000000000) time-ns)))) + (testing "tricky example" + (is (match? 4 (applicative/eval-key tricky-example :z + {::applicative/context manifold/context}))))) + +(testing "async works" + (let [[time-ns result] (criterium/time-body (applicative/eval-key test-env+delay-async + :d + {::applicative/context manifold/context}))] + (is (match? {:a 3 :b 6 :c 9} result)) + (is (match? (matchers/within-delta 100000000 1000000000) time-ns)))) + +(deftest manifold-eval-test + (testing "eval promise" + (is (match? {:a {::data/value 2} + :b {::data/value 1} + :c {::data/value 3}} + (applicative/eval test-env :c {::applicative/context manifold/context})))) + (testing "tricky example" + (is (match? {:x (data/value 1) + :y (data/value 2) + :a (data/value 3) + :b (data/value 4) + :c (data/value 5) + :w (data/value 4) + :z {::data/type :leaf + ::data/inputs #{:w}}} + (applicative/eval tricky-example :w {::applicative/context manifold/context}))))) + +(deftest manifold-eval-env-with-sequence + (testing "async response is equal to sync response" + (is (match? (-> (core/resolve :b env-with-sequence) (get :b) ::data/value) + (applicative/eval-key env-with-sequence :b)))) + (testing "sync=async for sequence with nil values" + (is (match? (-> (core/resolve :b env+sequence-with-nil-values) (get :b) ::data/value) + (applicative/eval-key env+sequence-with-nil-values :b)))) + (testing "sync=async for sequence returning nil values" + (is (match? (-> (core/resolve :b env+sequence-returning-nil-values) (get :b) ::data/value) + (applicative/eval-key env+sequence-returning-nil-values :b)))) + (testing "async version takes a third of the time of sync version + (runtime diff is 2 sec, within a tolerance of 3ms" + (let [[nanosec-sync _] (criterium/time-body (core/resolve :c env-with-sequence+delay-sync)) + [nanosec-async _] (criterium/time-body (applicative/eval-key env-with-sequence+delay :c))] + (is (match? (matchers/within-delta 8000000 2000000000) + (- nanosec-sync nanosec-async))))) + (testing "Actually computes the correct answers" + (is (match? [2 3 4] (applicative/eval-key env-with-sequence+delay :c))))) From db37f661b1887d6d44221c94f8c4c4e0253d396a Mon Sep 17 00:00:00 2001 From: Tiago Vidal Date: Tue, 14 Nov 2023 12:05:05 -0300 Subject: [PATCH 6/7] add deferred future and eval tests --- src/nodely/engine/applicative/manifold.clj | 12 ++++++++---- test/nodely/engine/applicative_test.clj | 17 +++++------------ 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/src/nodely/engine/applicative/manifold.clj b/src/nodely/engine/applicative/manifold.clj index 3ff3dfb..78c1474 100644 --- a/src/nodely/engine/applicative/manifold.clj +++ b/src/nodely/engine/applicative/manifold.clj @@ -6,9 +6,13 @@ (declare context) (extend-type manifold.deferred.SuccessDeferred - mp/Contextual - (-get-context [_] context) + mp/Extract + (-extract [it] + (try (deref it) + (catch java.util.concurrent.ExecutionException e + (throw (.getCause e)))))) +(extend-type manifold.deferred.Deferred mp/Extract (-extract [it] (try (deref it) @@ -31,7 +35,7 @@ mp/Monad (-mreturn [_ v] - (deferred/success-deferred v)) + (deferred/future v)) (-mbind [_ mv f] (deferred/chain mv (fn [v] @@ -39,7 +43,7 @@ mp/Applicative (-pure [_ v] - (deferred/success-deferred v)) + (deferred/future v)) (-fapply [_ pf pv] (deferred/chain (deferred/zip' pf pv) diff --git a/test/nodely/engine/applicative_test.clj b/test/nodely/engine/applicative_test.clj index 6c53d0b..ef9a4b0 100644 --- a/test/nodely/engine/applicative_test.clj +++ b/test/nodely/engine/applicative_test.clj @@ -229,13 +229,6 @@ (is (match? 4 (applicative/eval-key tricky-example :z {::applicative/context manifold/context}))))) -(testing "async works" - (let [[time-ns result] (criterium/time-body (applicative/eval-key test-env+delay-async - :d - {::applicative/context manifold/context}))] - (is (match? {:a 3 :b 6 :c 9} result)) - (is (match? (matchers/within-delta 100000000 1000000000) time-ns)))) - (deftest manifold-eval-test (testing "eval promise" (is (match? {:a {::data/value 2} @@ -256,18 +249,18 @@ (deftest manifold-eval-env-with-sequence (testing "async response is equal to sync response" (is (match? (-> (core/resolve :b env-with-sequence) (get :b) ::data/value) - (applicative/eval-key env-with-sequence :b)))) + (applicative/eval-key env-with-sequence :b {::applicative/context manifold/context})))) (testing "sync=async for sequence with nil values" (is (match? (-> (core/resolve :b env+sequence-with-nil-values) (get :b) ::data/value) - (applicative/eval-key env+sequence-with-nil-values :b)))) + (applicative/eval-key env+sequence-with-nil-values :b {::applicative/context manifold/context})))) (testing "sync=async for sequence returning nil values" (is (match? (-> (core/resolve :b env+sequence-returning-nil-values) (get :b) ::data/value) - (applicative/eval-key env+sequence-returning-nil-values :b)))) + (applicative/eval-key env+sequence-returning-nil-values :b {::applicative/context manifold/context})))) (testing "async version takes a third of the time of sync version (runtime diff is 2 sec, within a tolerance of 3ms" (let [[nanosec-sync _] (criterium/time-body (core/resolve :c env-with-sequence+delay-sync)) - [nanosec-async _] (criterium/time-body (applicative/eval-key env-with-sequence+delay :c))] + [nanosec-async _] (criterium/time-body (applicative/eval-key env-with-sequence+delay-sync :c {::applicative/context manifold/context}))] (is (match? (matchers/within-delta 8000000 2000000000) (- nanosec-sync nanosec-async))))) (testing "Actually computes the correct answers" - (is (match? [2 3 4] (applicative/eval-key env-with-sequence+delay :c))))) + (is (match? [2 3 4] (applicative/eval-key env-with-sequence+delay-sync :c {::applicative/context manifold/context}))))) From 55e8119610018504f5bd93c03a5a96be403dd633 Mon Sep 17 00:00:00 2001 From: Hugo Passos Date: Thu, 21 Dec 2023 16:33:34 -0300 Subject: [PATCH 7/7] merge main --- test/nodely/engine/applicative_test.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/nodely/engine/applicative_test.clj b/test/nodely/engine/applicative_test.clj index 4e7bbba..6f9baa6 100644 --- a/test/nodely/engine/applicative_test.clj +++ b/test/nodely/engine/applicative_test.clj @@ -325,7 +325,7 @@ (testing "eval promise" (is (match? 3 (applicative/eval-key test-env :c {::applicative/context core-async/context})))) (testing "async works" - (let [[time-ns result] (criterium/time-body (applicative/eval-key test-env+delay-async + (let [[time-ns result] (criterium/time-body (applicative/eval-key test-env+delay-core-async :d {::applicative/context manifold/context}))] (is (match? {:a 3 :b 6 :c 9} result))