This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2016-12-28
Channels
- # ai (1)
- # beginners (190)
- # boot (24)
- # cider (43)
- # cljsjs (3)
- # cljsrn (29)
- # clojars (6)
- # clojure (310)
- # clojure-dev (6)
- # clojure-nl (6)
- # clojure-russia (11)
- # clojure-spec (66)
- # clojure-uk (95)
- # clojurescript (103)
- # clojurewerkz (2)
- # core-async (9)
- # cursive (4)
- # datomic (5)
- # hoplon (163)
- # lein-figwheel (52)
- # off-topic (6)
- # om (6)
- # onyx (42)
- # perun (8)
- # re-frame (16)
- # reagent (10)
- # ring (7)
- # ring-swagger (1)
- # rum (1)
- # slack-help (2)
- # uncomplicate (1)
- # untangled (80)
I’m a little confused on fmap
vs bind
— according to the docs for clojure.test.check.generators/bind
: Create a new generator that passes the result of gen into function k. k should return a new generator.
fmap
also takes a generator, and applies some function to it. The only difference I can see is that in bind
, the function is responsible for returning a generator, and in fmap
, the function just returns data.
Is there some other difference I’m not seeing?
That's exactly the difference
bind is more powerful than fmap
so the idea is this is somewhat like Haskell with generators analogous to monads? that comparison doesn't make the most sense to me tho
Generators are a monad, yes
I expect that's literally true in quickcheck, which test.check is largely based on
i suppose in the sense that they're bound to a certain type? but i don't see how the monad laws could even possibly apply to generators
The first three make sense to me. I'll translate them to generators when I get to a keyboard
↑ I haven't grokked the fourth one but it probably works ¯\(ツ)/¯
i don't think that SO post is the best source. i've always only known three laws: left identity, right identity, and associativity. https://wiki.haskell.org/Monad_Laws
looks like it just skips the 3rd one
so the first two are equivalent
we could experiment to see if the two seem to do the same thing 🙂
what it does, or when it's useful?
bind+return is just fmap
so it's easier to use fmap
return is more often useful on its own
I'll go grep my source code to see when I use it
here's an example that uses it as the base case in a recursive generator: https://github.com/gfredericks/chess-clj/blob/89b2e5543534f82915a1aab67e026a326a0ed0a5/test/com/gfredericks/chess/generators.clj#L194
the associativity law looks right to me
it's just double-binding in two different ways; looks suspiciously trivial actually
so if you can associate that then you've met the third monad law...really the important one in that it lets you compose monads that encapsulate different typeclasses
I would need an example of such a composition to see what that means
it doesn't have a corollary in dynamic typing. that's why i always thought algo.monad was quite odd...
but it makes more sense with generators because they do in a sense have type signatures
yeah I've never seen the point of a monad library in clojure
it's really just a library of macros that needlessly replicate the functionality of a number of common haskell monads
too much you can't do and not enough help from the compiler
but this makes sense. you need bind in order to compose generators with different types
wow, now i'm really interested in uses of spec beyond things like quickcheck. i haven't seen other examples actually using generators to write code, although i think rich touched on it in his talk i saw
I'm not even sure what that means
generating code?
well, i only glossed over your chess example, but it seems you're using them to actually generate moves rather than to just test functions you've written?
no it's still for tests
it is generating moves, but only in service of generating legal positions, which is for testing
I don't think test.check generators are necessarily the best fit for non-testing purposes
generally they'll give you distributions that are a bit weird outside of testing
yeah, i've only noticed that now that i've started getting them working for whole projects...are they purposefully non-random or that's just a consequence of their implementation?
they are random
just skewed in their distribution, as a heuristic for catching bugs
i mean, for example, if i call (gen/sample (s/gen int?) n)
the size of the ints increase with n. initially they're quite small...which, as you said, makes sense for testing
yeah, that's half of the weirdness
that's demonstrating that gen/sample
uses an increasing size
parameter
but even if you fix size
, which you can do with gen/generate
, there are still elements of the "smaller things are worth trying more often" heuristic
more about sizing: https://github.com/clojure/test.check/blob/master/doc/growth-and-shrinking.md
ah, these are the docs i should have been looking at this whole time! i've been using this: http://clojure.github.io/clojure/branch-master/clojure.spec-api.html which just says everything is a wrapper of test.check macros
I'm trying to do a big documentation overhaul, so I'll try to look for ways to make discovery better too
yeah, your test.check docs are most useful for what i personally needed than most of what's in alex's guide. like i could have used gen/nat
earlier to avoid divide by zero errors and instead rolled my own
anyway, i think it'd be interesting to have something about the generator combinators and category theory. it's an interesting consequence of how they're typed that we're not used to in a dynamic language
i'd consider writing something like that for a wiki if i thought i could both make it accurate and substantial enough for anyone to care about 😛
that would be fun to read