Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Examples of Arbitraries by each test #3

Open
dakom opened this issue Aug 18, 2017 · 6 comments
Open

Examples of Arbitraries by each test #3

dakom opened this issue Aug 18, 2017 · 6 comments

Comments

@dakom
Copy link

dakom commented Aug 18, 2017

The tests currently contain type signatures such as this for Functor.composition:

// (f . g) <$> u = f <$> g <$> u

No doubt that's all the information one really needs to figure out what to do, but it requires some background in reading Haskell syntax.

It would be helpful to have examples of the types of Arbitraries that must be provided to each test, for an illustrative example:

u: Arbitrary for the test Functor. e.g. FooArb(jsc.number)
g: Arbitrary for a transformation function. e.g. jsc.constant(Math.sqrt),
f: Arbitrary for a different transformation function. e.g. jsc.constant(Math.abs)

This could also be made more accessible by perhaps using the fantasy-land type signature syntax without the Haskell symbols, but I think plain-English examples are helpful too.

@davidchambers
Copy link
Member

Providing example values (for f, g, and u in this case) is a great idea. I'll update #1 when I get a chance. :)

@dakom
Copy link
Author

dakom commented Aug 20, 2017

Oh, you had pointed me to the MaybeArb for help on understanding how to build an Arbitrary... just realized I should probably take a look at how you used it for testing. This is super helpful: https://github.com/sanctuary-js/sanctuary/blob/master/test/Maybe/Maybe.js

@davidchambers
Copy link
Member

I plan to merge #1 without this change, as I don't want to give myself an excuse to delay the release of this package any longer. I will of course welcome pull requests to make this project more approachable.

@variousauthors
Copy link

variousauthors commented May 8, 2020

I have also encountered this difficulty, and have come to share my story :D


    //  (.) <$> u <*> v <*> w = u <*> (v <*> w)
    composition: assert.forall3 (function(u, v, w) {
      return Z.Apply.test (u) &&
             Z.Apply.test (v) &&
             Z.Apply.test (w) &&
             equals (ap (ap (map (compose) (u)) (v)) (w),
                     ap (u) (ap (v) (w)));
    })

I just had a heck of a time implementing this test :D

From what I can see here...

map (compose) (u) implies that u must be some Functor (a -> b), because u must contain some value that can be composed.

Then we have ap (map (compose) (u)) (v) so v must contain (a -> b), from compose's signature.

And we have ap (ap (map (compose) (u)) (v)) (w) so w can contain anything, from ap's signature (I mean, it's value will be passed to the composition of u and v's value so it should have that type but whatever!)

So u and v must contain functions, and w is free.

v['fantasy-land/ap'](u['fantasy-land/ap'](a['fantasy-land/map'](f => g => x => f(g(x))))) 
is equivalent to 
v['fantasy-land/ap'](u)['fantasy-land/ap'](a)

Your u is what is mapped so it must be the a in the spec.

The result of a.map(compose) is then passed to your ap (_) (v) so your v must be the u in the spec.

Then your w must be the v in the spec.

In the spec there is no restriction on the type of v while the other variables must contain (a -> b). So first I was running this law like,

  const JustArb = jsc.number.smap(Just, just => just.value, show)
  const JustFnArb = jsc.fn(jsc.number).smap(Just, just => just.value, show)

  {
    const { composition } = laws.Apply(Z.equals)
    // v, u, a the order from the spec
    composition(JustArb, JustFnArb, JustFnArb)()
  }

That test fails. Then I noticed that your variables were in a different order, acceptable.

  const JustArb = jsc.number.smap(Just, just => just.value, show)
  const JustFnArb = jsc.fn(jsc.number).smap(Just, just => just.value, show)

  {
    const { composition } = laws.Apply(Z.equals)
    // u, v, a the order from these laws, with the labeling from the spec
    composition(JustFnArb, JustArb, JustFnArb)()
  }

That test fails. Then I did a bunch of console logging and equational reasoning, and that the labels differ by (v, u, w) => (u, a, v)

So finally I was able to run the test like this:

  const JustArb = jsc.number.smap(Just, just => just.value, show)
  const JustFnArb = jsc.fn(jsc.number).smap(Just, just => just.value, show)

  {
    const { composition } = laws.Apply(Z.equals)
    // u, v, a the order from these laws, with the labeling from the spec
    composition(JustFnArb, JustFnArb, JustArb)()
  }

Probably part of the confusion comes from fantasy-land's insistence on using the fluent style and your insistence on using the point-free style. This is what cause JustArb to move from first position in my brain (from the spec) to last position in your law.

Really this is an issue in my brain and I should change my neurons. It would be nice if the laws had comments describing their types. I'll be more careful, and carefully read the tests, and try to put the spec out of mind... but gosh! :D

Thanks for the sweet laws though!

Edit: Hmm! Maybe also part of the trouble came from the order of args in other laws. I think of the "subject" as being the one with the free type. So for example,

    // we are "testing" JustArb, it is the subject
    associativity(JustArb, fArb, gArb)()

But in the Apply test the "subject" in my brain is what you've put as the last argument.

@davidchambers
Copy link
Member

Thank you for sharing your experience. I agree that this module does not have a user-friendly interface. To avoid further confusion I think we should avoid making changes to argument order. ;)

@variousauthors
Copy link

Oh for sure! I think the OP has the right idea, that this can be addressed with documentation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants