This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-02-18
Channels
- # announcements (2)
- # aws (3)
- # beginners (35)
- # boot (10)
- # cider (33)
- # cljs-dev (22)
- # clojure (58)
- # clojure-belgium (1)
- # clojure-europe (8)
- # clojure-houston (1)
- # clojure-italy (47)
- # clojure-nl (2)
- # clojure-spec (4)
- # clojure-uk (39)
- # clojurescript (12)
- # cursive (18)
- # data-science (1)
- # datomic (2)
- # emacs (24)
- # figwheel-main (29)
- # fulcro (24)
- # hoplon (14)
- # juxt (6)
- # kaocha (3)
- # nrepl (6)
- # off-topic (64)
- # om (1)
- # om-next (1)
- # pathom (21)
- # pedestal (18)
- # planck (40)
- # protorepl (1)
- # re-frame (15)
- # reagent (7)
- # reitit (16)
- # shadow-cljs (184)
- # spacemacs (4)
- # test-check (33)
I wanted to generate arguments for subs
:
(def subs-args-gen
(gen/fmap
(fn [[str [start end]]]
(if end
[str start end]
[str start]))
(gen/bind
(gen/string)
(fn [s]
(gen/tuple (gen/return s)
(gen/bind
(gen/choose 0 (count s))
(fn [start]
(gen/one-of
[(gen/tuple (gen/return start))
(gen/tuple (gen/return start)
(gen/choose start (count s)))]))))))))
(comment
(gen/sample subs-args-gen)
;; (["" 0] ["k" 1 1] ["" 0] ["
_" 0 0] ["" 0] ["¥/" 0] ["µ" 0] ["Þ¦\n" 3] ["" 0] ["\tsÈaíå" 1])
)
It feels a bit verbose, maybe there was a nicer way to do this?that's a good one
I'm trying to think of something that shrinks better than all the gen/bind
s
and has a good distribution
those things can trade off with readability/simplicity sometimes
here's a relatively simple approach
(gen/let [[s start end use-end?]
(gen/tuple gen/string gen/nat gen/nat gen/boolean)]
(let [start (min start (count s))
end (min end (count s))
[start end] (sort [start end])]
(cond-> [s start] use-end? (conj end))))
there might be edge cases there with (count s)
, I'm not sure how subs
works
and you might complain that this will be more likely than you'd want to generate args that are equal to (count s)
, and if that bothers you then you could do something like use (gen/choose 0 1000000)
for start
and end
and then scale them down to the size of the string
@gfredericks cool, I did not know about gen/let
So I got it right then I think
I like the boolean idea:
(gen/bind
(gen/tuple (gen/string) (gen/boolean))
(fn [[s end?]]
(if end?
(gen/bind
(gen/choose 0 (count s))
(fn [start]
(gen/tuple
(gen/return s)
(gen/return start)
(gen/choose start (count s)))))
(gen/tuple
(gen/return s)
(gen/choose 0 (count s))))))
the sorting trick is also good for generating ordered numbers w/o having to do it in stages
I probably go overboard on avoiding gen/bind
you can actually write this fairly simply by using multiple clauses in gen/let
(which expands to gen/bind
)
(gen/let [s gen-string, start (gen/choose 0 (count s)), end (gen/choose start (count s)), use-end? gen/boolean] (cond-> [s start] use-end? (conj end)))
if gen/tuple accepted nil, then you could write:
(fn [start]
(gen/tuple
(gen/return s)
(gen/return start)
(when end? (gen/choose start (count s)))))
I just have this instinct to not use gen/bind
if it can be avoided, which is probably not worth the effort in a lot of cases
not too new
maybe new in 0.9.0?
yeah:
(g/let [s g/string
start (gen/choose 0 (count s))
end (gen/choose start (count s))
use-end? (gen/boolean)]
(cond-> [s start] use-end? (conj end)))
works. awesome.yeah; it's just sugar over gen/fmap
and gen/bind