This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-02-19
Channels
I have a question on how to make a match optional while still being able to capture the match if it's there. Example and description in 🧵
Here's some example data:
{:tag :note,
:attrs
{:default-x "148.88",
:default-y "-10.00",
:dynamics "71.11",
:measure "1",
:voice "P1"},
:content
({:tag :pitch,
:attrs {},
:content
({:tag :step, :attrs {}, :content ("D")}
{:tag :alter, :attrs {}, :content ("-1")}
{:tag :octave, :attrs {}, :content ("5")})}
{:tag :duration, :attrs {}, :content ("1")}
{:tag :voice, :attrs {}, :content ("1")}
{:tag :type, :attrs {}, :content ("16th")}
{:tag :stem, :attrs {}, :content ("down")}
{:tag :beam, :attrs {:number "1"}, :content ("continue")}
{:tag :beam, :attrs {:number "2"}, :content ("continue")})}
Here's the pattern I'm using to match it, which makes good use of meander's $
operator:
(defn extract-essential-info [note]
(meander/find note
(meander/and
{:tag :note
:attrs {:measure ?measure :voice ?voice}}
(meander/$ {:tag :step :content (?key)})
(meander/$ {:tag :alter :content (?alteration)})
(meander/$ {:tag :octave :content (?octave)})
(meander/$ {:tag :duration :content (?duration)})
(meander/$ {:tag :type :content (?type)}))
{:tag :note
:measure ?measure
:voice ?voice
:key ?key
:alteration ?alteration
:octave ?octave
:duration ?duration
:type ?type}))
My problem is that sometimes I don't have an :alter
tag anywhere in the structure, and in that case the match fails. How would I say that if the :alter
match fails, I'd like to have :alteration 0
in my map?
Possible solution, extending with another clause for when the pattern is not there, like:
(defn extract-essential-info [note]
(meander/find note
(meander/and
{:tag :note
:attrs {:measure ?measure :voice ?voice}}
(meander/$ {:tag :step :content (?key)})
(meander/$ {:tag :alter :content (?alteration)})
(meander/$ {:tag :octave :content (?octave)})
(meander/$ {:tag :duration :content (?duration)})
(meander/$ {:tag :type :content (?type)}))
{:tag :note
:measure ?measure
:voice ?voice
:key ?key
:alteration ?alteration
:octave ?octave
:duration ?duration
:type ?type}
(meander/and
{:tag :note
:attrs {:measure ?measure :voice ?voice}}
(meander/$ {:tag :step :content (?key)})
(meander/not (meander/$ {:tag :alter :content (?alteration)}))
(meander/$ {:tag :octave :content (?octave)})
(meander/$ {:tag :duration :content (?duration)})
(meander/$ {:tag :type :content (?type)}))
{:tag :note
:measure ?measure
:voice ?voice
:key ?key
:alteration 0
:octave ?octave
:duration ?duration
:type ?type}))
but this feels wasteful and it's subject to combinatorial explosion, I was hoping in a smarter encodingCan you do something like this?
(m/rewrites '{:note ({:pitch ({:step ("D")}
{:alter ("-1")}
{:octave ("5")})}
{:duration ("1")}
{:voice ("1")}
{:type ("16th")}
{:stem ("down")}
{:beam ("continue")}
{:beam ("continue")})}
(m/$ {:step (?key)}) {:key ?key}
(m/$ {:alter (?alteration)}) {:alteration ?alteration}
(m/$ {:octave (?octave)}) {:octave ?octave}
(m/$ {:duration (?duration)}) {:duration ?duration}
(m/$ {:type (?type)}) {:type ?type}
(m/$ {:measure (?measure)}) {:measure ?measure}
(m/$ {:voice (?voice)}) {:voice ?voice})
gives
({:key "D"} {:alteration "-1"} {:octave "5"} {:duration "1"} {:voice "1"} {:type "16th"})
Actually this.
(->> (m/rewrites '{:tag :note,
:attrs {:default-x "148.88",
:default-y "-10.00",
:dynamics "71.11",
:measure "1",
:voice "P1"},
:content ({:tag :pitch,
:attrs {},
:content ({:tag :step, :attrs {}, :content ("D")}
{:tag :alter, :attrs {}, :content ("-1")}
{:tag :octave, :attrs {}, :content ("5")})}
{:tag :duration, :attrs {}, :content ("1")}
{:tag :voice, :attrs {}, :content ("1")}
{:tag :type, :attrs {}, :content ("16th")}
{:tag :stem, :attrs {}, :content ("down")}
{:tag :beam, :attrs {:number "1"}, :content ("continue")}
{:tag :beam, :attrs {:number "2"}, :content ("continue")})}
(m/$ {:tag :step :content (?key)}) {:key ?key}
(m/$ {:tag :alter :content (?alteration)}) {:alteration ?alteration}
(m/$ {:tag :octave :content (?octave)}) {:octave ?octave}
(m/$ {:tag :duration :content (?duration)}) {:duration ?duration}
(m/$ {:tag :type :content (?type)}) {:type ?type}
(m/$ {:tag :note :attrs {:measure ?measure :voice ?voice}}) {:measure ?measure :voice ?voice})
(reduce into))
gives
{:measure "1", :voice "P1", :key "D", :alteration "-1", :octave "5", :duration "1", :type "16th"}
@UA7E6DU04 Did that help?