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 clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
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 clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to