Fork me on GitHub
#clojure-spec
<
2016-12-28
>
joshjones20:12:59

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?

gfredericks21:12:40

That's exactly the difference

gfredericks21:12:40

bind is more powerful than fmap

sophiago21:12:26

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

gfredericks21:12:15

Generators are a monad, yes

gfredericks21:12:56

I expect that's literally true in quickcheck, which test.check is largely based on

sophiago22:12:15

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

gfredericks22:12:15

The first three make sense to me. I'll translate them to generators when I get to a keyboard

gfredericks23:12:16

↑ I haven't grokked the fourth one but it probably works ¯\(ツ)

sophiago23:12:49

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

gfredericks23:12:35

looks like it just skips the 3rd one

sophiago23:12:37

the associativity one in your example is unclear to me

gfredericks23:12:41

so the first two are equivalent

sophiago23:12:58

the first two make sense. i didn't know there was a gen/return either!

gfredericks23:12:00

we could experiment to see if the two seem to do the same thing 🙂

sophiago23:12:13

i'm confused about the purpose of gen/return from reading the api docs

gfredericks23:12:25

what it does, or when it's useful?

sophiago23:12:40

just what it does

sophiago23:12:05

i suppose returns a generator? lol

sophiago23:12:19

so maybe i should have asked the second question...

sophiago23:12:45

like in what case would you bind a generator and then return it?

gfredericks23:12:22

bind+return is just fmap

gfredericks23:12:28

so it's easier to use fmap

gfredericks23:12:41

return is more often useful on its own

gfredericks23:12:56

I'll go grep my source code to see when I use it

gfredericks23:12:05

the associativity law looks right to me

gfredericks23:12:29

it's just double-binding in two different ways; looks suspiciously trivial actually

sophiago23:12:37

woah, that's a really cool application of generators!

sophiago23:12:23

yes...because >>= is the bind operator 🙂

sophiago23:12:24

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

sophiago23:12:04

this would make a good blog post or something to that effect

gfredericks23:12:04

I would need an example of such a composition to see what that means

sophiago23:12:11

it doesn't have a corollary in dynamic typing. that's why i always thought algo.monad was quite odd...

sophiago23:12:40

but it makes more sense with generators because they do in a sense have type signatures

gfredericks23:12:40

yeah I've never seen the point of a monad library in clojure

sophiago23:12:14

it's really just a library of macros that needlessly replicate the functionality of a number of common haskell monads

gfredericks23:12:14

too much you can't do and not enough help from the compiler

sophiago23:12:17

but this makes sense. you need bind in order to compose generators with different types

sophiago23:12:07

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

gfredericks23:12:37

I'm not even sure what that means

gfredericks23:12:45

generating code?

sophiago23:12:31

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?

gfredericks23:12:24

no it's still for tests

gfredericks23:12:40

it is generating moves, but only in service of generating legal positions, which is for testing

sophiago23:12:07

yeah i looked at it again. at first i thought you were using it to play chess

gfredericks23:12:10

I don't think test.check generators are necessarily the best fit for non-testing purposes

gfredericks23:12:40

generally they'll give you distributions that are a bit weird outside of testing

sophiago23:12:41

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?

gfredericks23:12:25

they are random

gfredericks23:12:42

just skewed in their distribution, as a heuristic for catching bugs

sophiago23:12:20

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

gfredericks23:12:45

yeah, that's half of the weirdness

gfredericks23:12:01

that's demonstrating that gen/sample uses an increasing size parameter

gfredericks23:12:33

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

sophiago23:12:08

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

gfredericks23:12:48

I'm trying to do a big documentation overhaul, so I'll try to look for ways to make discovery better too

sophiago23:12:27

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

sophiago23:12:25

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

sophiago23:12:54

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 😛

gfredericks23:12:10

that would be fun to read