-
Notifications
You must be signed in to change notification settings - Fork 30
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
Improved integral shrink trees to match behavior of binary search #239
Improved integral shrink trees to match behavior of binary search #239
Conversation
Haskell Hedgehog now has its own version of this PR in hedgehogqa/haskell-hedgehog#413. Waiting for that to be completed before resuming work on this PR. |
Work on this PR can resume because the corresponding PR hedgehogqa/haskell-hedgehog#413 in Haskell Hedgehog has been merged. I will do this soon. |
f70daff
to
5098cf7
Compare
5098cf7
to
06f96f5
Compare
ec74140
to
e242274
Compare
This PR is now ready for review.
Actually, it is easy to avoid the compile errors. Just define a local function to do the recursion and the containing function can be inlined. I also added several tests. I am now confident that this code is bug-free. After writing the tests, I found one bug in
I now think the code is pretty. I modified This code is not a port of @HuwCampbell's code in PR hedgehogqa/haskell-hedgehog#413. I like this code better, and I think there is a chance that @HuwCampbell might like it more too based on this comment in our Slack conversation since this code is a recursive function on the values.
|
🏓 @HuwCampbell 👀 (You said, one day you might want to learn to read F#, I think this is a beautiful example to start.) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💯
Co-authored-by: Nikos Baxevanis <nikos.baxevanis@gmail.com>
(I thought I already made this comment, but it must have been lost when GitHub gave me a 500 error.) (For those watching the email, the first time the build failed was because I accidently had a compile error. I force pushed a fix for that.) The fable-tests build is failing because of a 500 error while trying to obtain its GitHub Action. I was just able to download the Action using the link it he logs. Seems like we should just queue the build again. |
testCase "createTree correct for 0,7" <| fun _ -> | ||
let actual = Shrink.createTree 0 7 |> Tree.map (sprintf "%A") |> Tree.renderList | ||
let expected = | ||
[ "7" | ||
"├-0" | ||
"├-4" | ||
"| ├-2" | ||
"| | └-1" | ||
"| └-3" | ||
"└-6" | ||
" └-5" ] | ||
expected =! actual |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks great.
It looks really good, I was planning on doing something like the |
Done. All checks have passed now. |
@TysonMN, shall we merge this? |
Yep, I think this is ready |
I find the plus one / minus one a bit odd. let inline createTree (destination : ^a) (x : ^a) =
let rec binarySearchTree (destination : ^a) (x : ^a) =
let xs =
towards destination x
|> Seq.pairwise
|> Seq.map (fun (d, x) -> binarySearchTree d x)
Node (x, xs)
if destination = x then
Node (x, Seq.empty)
else
binarySearchTree destination x
|> Tree.addChildValue destination This looks semantically more similar to what I have in the Haskell version. Edit: If this doesn't work for you I'm happy for it to go ahead as is. |
I would definitely prefer not to be adding and subtracting Interesting though, there should never be an under or over flow. Your code causes most of the tests to fail, but I see where you are going. I defined I think that should work. Probably just have to adjust |
The behavior preserving transformation is to subtract one from all arguments passed in for Good catch @HuwCampbell! Now |
And what do ya know? The implementation of Now the code is still correct and even prettier! Definitely time to merge :D |
That's heaps better. |
That's exactly right; and what my version in Haskell does. They are essentially identical now apart from the tree wrapping and unwrapping over there (which I aim to remove at some point). |
Great work and awesome @hedgehogqa org wide collaboration 🦔 |
We should blog/write about this stuff one day! |
Fixes #224
This PR changes the implementation of
Gen.integral
so that the shrink tree corresponds to the choices that binary search would make.This is a draft PR because more testing is needed. I "manually" tested it with
0
fordestination
and4
forx
, and the resulting tree matches my expectation, which I showed in #224 (comment).I don't know how to create an automated test for this. The main problem is that calling
Gen.integral
includes randomness from the call toRandom.integral
. If I try to extract thecreateTree
function to avoid that randomness, then I get these compile errors and warning.The impression I get is that it is not possible to define a function that is both recursive and inlined. Is there a way to expose the
createTree
function for testing?The code is not very pretty. For example, I reused
Shrink.towards
but then hacked the output to fit the one case I was testing. I wouldn't be surprised if I missed more edge cases, but I do think it is "mostly" correct. I would prefer to create some automated unit tests before simplifying the code.Some good news is that all existing tests still pass.