Skip to content

Test the empty type case#2

Draft
hawnzug wants to merge 3 commits into
mainfrom
test-empty-type
Draft

Test the empty type case#2
hawnzug wants to merge 3 commits into
mainfrom
test-empty-type

Conversation

@hawnzug

@hawnzug hawnzug commented Jul 14, 2021

Copy link
Copy Markdown
Owner

No description provided.

@hawnzug

hawnzug commented Jul 14, 2021

Copy link
Copy Markdown
Owner Author

It seems that QuickCheck doesn't work well with the empty type case because of the Arbitrary typeclass. For example, consider the property

prop :: [a] -> Bool

instantiated with Void. We don't have Arbitrary [Void] because

Arbitrary a => Arbitrary [a]

How about giving a warning when the empty type case is needed and let the user check it by hand? @favonia

@favonia

favonia commented Jul 14, 2021

Copy link
Copy Markdown

It seems that QuickCheck doesn't work well with the empty type case because of the Arbitrary typeclass. For example, consider the property

prop :: [a] -> Bool

instantiated with Void. We don't have Arbitrary [Void] because

Arbitrary a => Arbitrary [a]

How about giving a warning when the empty type case is needed and let the user check it by hand? @favonia

I think we should strive to be maximally useful for practical purposes. For example, if QuickCheck is of no help but we could prove that all functions will be observationally equal (with the Haskell \bot ignored), then we can skip the test completely. In this case, we can write code for the special cases [a]. I don't feel we are bound by theoretical purity and we should be free to deliver whatever that is maximally useful. We or someone else can work out elegant theory from practical hacks later.

@hawnzug

hawnzug commented Jul 14, 2021

Copy link
Copy Markdown
Owner Author

Here is my rough idea to implement custom Arbitrary for empty type case. Consider the type

data D a = D1 | D2 | D3 a

along with the Arbitrary instance

Arbitrary a => Arbitrary (D a)

implemented by the user which generates D1, D2, or D3 with the same probability, to give custom Arbitrary instance for D Void, it first invokes the user-defined arbitrary for D. If the empty branch (D3) is chosen, it could either:

  1. call arbitrary repeatedly until D1 or D2 is generated
  2. simply fallback to a nonempty branch (D1 or D2)

The first approach might have performance issue (?) and the second one will break the original probability distribution. Personally I prefer the second one. Any ideas?

@favonia

favonia commented Jul 14, 2021

Copy link
Copy Markdown

Here is my rough idea to implement custom Arbitrary for empty type case. Consider the type

data D a = D1 | D2 | D3 a

along with the Arbitrary instance

Arbitrary a => Arbitrary (D a)

implemented by the user which generates D1, D2, or D3 with the same probability, to give custom Arbitrary instance for D Void, it first invokes the user-defined arbitrary for D. If the empty branch (D3) is chosen, it could either:

1. call `arbitrary` repeatedly until `D1` or `D2` is generated

2. simply fallback to a nonempty branch (`D1` or `D2`)

The first approach might have performance issue (?) and the second one will break the original probability distribution. Personally I prefer the second one. Any ideas?

I want to double check my understanding. Will data D a = D1 a | D2 a cause infinite looping?

@hawnzug

hawnzug commented Jul 14, 2021

Copy link
Copy Markdown
Owner Author

I want to double check my understanding. Will data D a = D1 a | D2 a cause infinite looping?

Yes and no. It will first see that D Void is empty so it won't test the empty type case.

Oh sorry. If you mean the case Either Bool (D a), it will cause infinite looping.

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

Successfully merging this pull request may close these issues.

2 participants