Last active
December 27, 2020 06:21
-
-
Save stevebuik/e63735d99fca94041120f9b0e25b616d to your computer and use it in GitHub Desktop.
example of Malli tree nodes using a :multi for the nodes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns recursive-multi-malli | |
(:require [malli.core :as m] | |
[malli.util :as mu] | |
[malli.error :as me] | |
[criterium.core :as criterium])) | |
(def simple-tree-node | |
[:schema {:registry {::type [:enum :blue :green] | |
::children [:vector [:ref ::node]] | |
::node [:multi {:dispatch :type} | |
[:blue [:map | |
[:type {:optional false} ::type] | |
[:children {:optional true} ::children] | |
[:name string?] | |
[:count pos-int?] | |
]] | |
[:green [:map | |
[:type {:optional false} ::type] | |
[:children {:optional true} ::children] | |
[:name string?] | |
[:size pos-int?]]]]}} | |
::node]) | |
(def sample1 {:type :blue | |
:name "foo" | |
:count 2}) | |
(def sample2 {:type :blue | |
:name "foo" | |
:count 2 | |
:children [{:type :green | |
:name "bar" | |
:size 4}]}) | |
(def sample3 {:type :blue | |
:name "foo" | |
:count 2 | |
:children [{:type :green | |
:name "bar" | |
:size 4} | |
{:type :green | |
:name "bar" | |
:size 4}]}) | |
(def sample4 {:type :blue | |
:name "foo" | |
:count 2 | |
:children [{:type :green | |
:name "bar" | |
:size 4} | |
{:type :green | |
:name "bar" | |
:size 4} | |
{:type :green | |
:name "bar" | |
:size 4}]}) | |
(def simple-tree-node-merged | |
[:schema {:registry {::type [:enum :blue :green] | |
::children [:vector [:ref ::node]] | |
::common [:map | |
[:type {:optional false} ::type] | |
[:children {:optional true} ::children] | |
[:name string?]] | |
::node [:multi {:dispatch :type} | |
[:blue [:merge ::common | |
[:map | |
[:count pos-int?]]]] | |
[:green [:merge ::common | |
[:map | |
[:size pos-int?]]]]]}} | |
::node]) | |
(comment | |
; check validation works | |
(clojure.pprint/pprint (me/humanize (m/explain simple-tree-node sample1))) | |
; without children | |
(let [validator (m/validator simple-tree-node)] | |
(criterium/quick-bench (validator sample1))) | |
; 15 x slower with one child | |
(let [validator (m/validator simple-tree-node)] | |
(criterium/quick-bench (validator sample2))) | |
; 30 x slower with 3 children | |
(let [validator (m/validator simple-tree-node)] | |
(criterium/quick-bench (validator sample3))) | |
; 45 x slower with 4 children | |
(let [validator (m/validator simple-tree-node)] | |
(criterium/quick-bench (validator sample4))) | |
; 45 x slower with one child using :merge | |
(let [validator (m/validator simple-tree-node-merged {:registry (merge (m/default-schemas) | |
(mu/schemas))})] | |
(criterium/quick-bench (validator sample2))) | |
) | |
; observations: | |
; 1. combining recursion and multi is 2 x slower than recursion alone. see https://gist.github.com/stevebuik/e4f3475e46dd5ebb1de7707438fa073f | |
; 2. big perf slow-down when children are present | |
; 3. perf is then linear for deep or broad trees | |
; 4. using :merge instead of inline is 3 x slower | |
; Q: are there any further perf optimizations available? | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment