Fork me on GitHub
#clojure-spec
<
2017-08-01
>
athos04:08:05

@plins I think (s/keys :req-un [(or ::a ::b)]) would be a smarter solution

misha10:08:17

@athos is this even legal?

athos10:08:08

@misha Of course! s/keys docstring refers to this feature.

misha10:08:57

not sure how I missed it then. anyway: wow, nice

misha11:08:28

is "mutual exclusiveness" and/or "orthogonality" of a set of the predicates is even approachable, let alone provable automatically (e.g. during testing with spec)? Does it imply complete exhaustion of the possible input combinations?

misha11:08:33

Context is: In Harel's charts (or UML state diagrams), state can have multiple transitions to mutually exclusive states, via the same trigger. What ensures that system ends up in a valid state, is a combination of guards (predicates) on those transitions, which should guarantee mutual exclusiveness of the guard outcome. I want to try to automatically test whether guards on a set of transitions are mutually exclusive. e.g. :

(def FSM
  {:A {:B {:trigger :a :guard pos-int?}
       :C {:trigger :a :guard neg-int?}}})
Current state is :A. Some event triggers transition :a. Machine has to switch to either :B or :C, but not both. I want to make sure guards (`pos-int?`, and neg-int? in this case) are mutually exclusive. Automatically. At compile time.

misha11:08:13

Is it even possible? Or the best I can do is to just issue a "dude, make sure [:A :B :guard] and [:A :C :guard] are mutually-exclusive" warning?

gfredericks11:08:16

there's no general solution to that, but you could write a test.check property that asserts it

gfredericks11:08:37

if you have a meaningful generator for the state

gfredericks11:08:55

or whatever it is that's getting passed to the guards

misha11:08:38

@gfredericks the complication with this, is the huge arity of the guards: they need to accept app-db, whole-machine, and event trigger with its args harold

misha11:08:56

where for machine I may supply generator, but app-db and trigger args structure, contents, and specs are entirely up to user

gfredericks11:08:34

sounds tough 🙂 you can validate at compile time of course

misha11:08:48

and for even as simple as a single string arg, exhausting 2 arbitrary predicates (e.g. with regexps inside) is doubtful, I think(?)

gfredericks11:08:14

but for a turing-complete language you can't in general check if two predicates are mutually exclusive

gfredericks11:08:30

regexes might be doable, depending on the details

gfredericks11:08:38

not worth it though

gfredericks11:08:53

just a theoretical curiosity

misha11:08:56

I feel... relief 😄

misha11:08:41

what if the predicate's source code is available? Is there something to, say, reverse-engineer things like (select-keys app-db [:foo :bar]) to reduce relevant input scope? Or at least to deduce, that guards, in fact, are orthogonal (which is useful too, but I forgot why just now)?

gfredericks11:08:11

definitely for special cases

gfredericks11:08:37

but the general case impossibility I mentioned earlier applies to source or compiled or whatever else

misha11:08:35

it'd be useful to cover at least some basic cases, because most of (UI) FSMs would actually use pretty basic guards

misha11:08:56

(There are at least 2 implementation options: 1) pseudo states, where you define a fork in the transition as a separate state, and just ask to for cond/case guard there. 2) duplicate transitions with separate boolean guards, which (implicitly) need to be mutually-exclusive. I am exploring (2) at the moment, to make literal FSM definition less verbose.)

mfikes12:08:24

The solution to my s/cat in s/cat question yesterday was, of course, s/spec:

(s/fdef none? :args (s/cat :ingredient (s/spec ::ingredient)))

jpmonettas15:08:54

if someone finds it useful, just released a version of https://github.com/jpmonettas/inspectable with clojure and clojuresript support, also with an enhanced browser that shows the spec together with a sample