7

Suppose, I want to test the following associativity property for Sum with the help of hedgehog library in Haskell:

a <> (b <> c) ≡ (a <> b) <> c

I have actually two ways to generate random input.

1. Generate all in Gen (using Gen's Applicative and Monad instances)

genTriple :: Get (Int, Int, Int)
genTriple = liftA3 (,,) Gen.enumBounded Gen.enumBounded Gen.enumBounded

prop_assoc :: Property
prop_assoc = property $ do
  (a, b, c) <- forAll genTriple
  (Sum a <> Sum b) <> Sum c === Sum a <> (Sum b <> Sum c)

2. Generating each field under forAll

prop_assoc :: Property
prop_assoc = property $ do
  a <- forAll Gen.enumBounded
  b <- forAll Gen.enumBounded
  c <- forAll Gen.enumBounded
  (Sum a <> Sum b) <> Sum c === Sum a <> (Sum b <> Sum c)

I wonder, what is the difference between two approaches? Does it somehow affect performance or parallelization or randomness?

Shersh
  • 9,019
  • 3
  • 33
  • 61
  • Since they both use `Gen`, isn't your result fundamentally the same? You're using three calls to `Gen.enumBounded` in each case. Why would these be different? – jkeuhlen Apr 10 '18 at 16:16
  • @jkeuhlen `forAll` works under `property` function within `PropertyT IO ()` monad. First example uses `Gen` monad. Since different monads are used the behavior can be potentially different (depending on `Monad` instances for those types). Or, simple explanation: there're multiple different ways to do smth so I wonder what is the difference between them. – Shersh Apr 10 '18 at 19:28
  • Both examples use the `Property` monad don't they? Maybe I'm missing something, but one is written in an applicative style and the other in sequential monadic style. They use the same generator in the same monad. It should have the exact same result. – jkeuhlen Apr 10 '18 at 21:36
  • @jkeuhlen The difference is in number of times I cal `forAll` function. Implementation of `forAll` function with multiple calls to `forAll` inside `PropertyT` is not equal to implementation of `Applicative` instance for `Gen` type. – Shersh Apr 10 '18 at 21:48
  • `liftA3` appeals to the properties of applicative functors, opening up the possibility of running computations in parallel. On the other hand, the `do` notation desugars to the bind operator, which is inherently sequential (as each computation builds on the result of the previous one). – Regis Kuckaertz Apr 15 '18 at 15:47

1 Answers1

0

Package maintainers answered this question under corresponding GitHub issue:

Shersh
  • 9,019
  • 3
  • 33
  • 61
  • This is useful, but it's a link-only answer. You should include the actual information here. – dfeuer Apr 16 '18 at 19:54
  • @dfeuer Maybe, but I'd prefer not to do this because (1) I don't know much about this to add something else; (2) I want to avoid duplicating text (anyone can follow the link); (3) If I copy-paste text it could become outdated because GitHub issue can be updated. – Shersh Apr 16 '18 at 21:42
  • You can always include the link, but SO policy frowns on link-only answers. Perhaps you can copy/paste with attribution and link. Make this answer Community Wiki to avoid taking credit and to encourage others to edit. – dfeuer Apr 16 '18 at 21:46
  • @dfeuer I made community wiki. I have no problems with this :) – Shersh Apr 16 '18 at 23:00
  • I meant I suggested making it CW *and* copying the text into it. It's still a link-only answer! – dfeuer Apr 17 '18 at 01:05