A few thoughts on your design and a possible solution to your problem. Firstly if we are concerned about the correct ordering of values over time, then it sounds like we are dealing with something that contains hidden mutable state. That hidden state is a can be problematic. In general, when working with core.async I try to encourage everyone to avoid situations where the data received on a channel demands a specific ordering, not only does it introduce component coupling (both sides must agree to the protocol), but it also involves mutable state.
One possible way to spec this, however, is to express your state machine (because that's what you have here), as a finite state machine. That is to say, don't spec the order of events, spec the state transitions: a -> b b -> c c -> d c -> b Each of those could be a spec, and then you could pass in both the old and new state to each step of the state machine. In this way your state machine remains pure, and you can spec pairs of states. I.e. an event to move to state "d" would fail to validate if the previous state was "a". On Fri, Aug 5, 2016 at 12:08 PM, Alex Miller <[email protected]> wrote: > There are a variety of possible extensions to what is currently offered by > spec wrt regex derivatives but that's up to Rich. > > > On Friday, August 5, 2016 at 12:37:15 PM UTC-5, Russell Mull wrote: >> >> Suppose you have a reactive process, something that receives a message, >> processes it, updates its, state, and repeats. For example: >> >> (go-loop [s :initial] >> (case (<! input-chan) >> :a (recur :processing) >> :b (recur :stopping) >> nil [:success])) >> >> In this contrived example, there are some implied valid state transitions: >> :initial -> :processsing >> :processing ->: :processing >> :processing -> :stopping >> :stopping -> (done) >> >> This is pretty easy to write as a regular expression, using clojure.spec: >> (s/def ::state-seq >> (s/cat :s1 #{:initial} >> :s2 (s/+ #{:processing}) >> :s3 #{:stopping})) >> >> But with the clojure.spec api, we'd have to store the whole sequence of >> states and validate it once at the end. To be useful for specifying a >> sequence of values that are spread out over time, I'd really like to be >> able to partially evaluate the schema with a single value when it is at >> hand. The API doesn't expose this, but the implementation appears to >> support it. It would require the ability to track the intermediate states >> of the regex derivative, and the ability to do an explicit complete >> (nullable) check. It could look something like this: >> (go-loop [st :initial, sch (s/get-spec ::state-seq)] >> (let [[valid sch'] (s/partial-valid? sch st)] >> (when-not (valid) >> [:error "everything is terrible"] >> (throw "everything is terrible")) >> (case (<! input-chan) >> :a (recur :processing sch') >> :b (recur :stopping sch') >> nil (if (s/complete? sch') >> [:success] >> [:error "input channel closed, but we weren't in a done >> state"])))) >> >> >> This could also be useful for specifying something about the order of >> values expected on a channel: >> (s/def ::channel-message-seq >> (s/cat :s1 #{:a} >> :s2 (s/+ #{:b}))) >> >> (go-loop [sch (s/get-spec ::channel-message-seq)] >> (let [[sch' msg] (s/partial-conform sch (<! input-chan)) >> (case msg >> :a (recur sch') >> :b (recur sch') >> ::s/invalid [:error "got unexpected message"]))) >> >> There are of course many convenient ways this could be packaged. >> >> Is it feasible or desirable to add this to clojure.spec? >> >> - Russell Mull >> > -- > You received this message because you are subscribed to the Google > Groups "Clojure" group. > To post to this group, send email to [email protected] > Note that posts from new members are moderated - please be patient with > your first post. > To unsubscribe from this group, send email to > [email protected] > For more options, visit this group at > http://groups.google.com/group/clojure?hl=en > --- > You received this message because you are subscribed to the Google Groups > "Clojure" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to [email protected]. > For more options, visit https://groups.google.com/d/optout. > -- “One of the main causes of the fall of the Roman Empire was that–lacking zero–they had no way to indicate successful termination of their C programs.” (Robert Firth) -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to [email protected] Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to [email protected] For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. For more options, visit https://groups.google.com/d/optout.
