-
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
Rearrange parameters for better chaining. #266
Conversation
The functions fsharp-hedgehog/src/Hedgehog/Gen.fs Lines 46 to 48 in 7058b4c
should have its arguments reversed to let apply (gx : Gen<'a>) (gf : Gen<'a -> 'b>) : Gen<'b> = Then given let flip f b a = f a b
let g = (Gen.constant 1) we can replace (fun a b c d e -> a + b + c + d + e)
|> flip Gen.map g
|> Gen.map4 g g g g with (fun a b c d -> a + b + c + d)
|> flip Gen.map g
|> Gen.apply g
|> Gen.apply g
|> Gen.apply g Clearly the advantage of the latter is that it scales to a (curried) function with any number of inputs. Just as I explained in #265 (comment), the arguments to the function named I am not actually requesting that Instead, I am specifically requesting that the arguments to Also, I find it annoying to call (fun a b c d -> a + b + c + d)
|> Gen.apply1 g
|> Gen.apply g
|> Gen.apply g
|> Gen.apply g Therefore, I also suggest adding this |
@TysonMN There are a few ways to skin that cat, you could also write the applicative chain like this: let g = Gen.constant 1
Gen.success (fun a b c d -> a + b + c + d)
|> Gen.apply g
|> Gen.apply g
|> Gen.apply g
|> Gen.apply g Or like this: let (<*>) = Gen.apply
let (<!>) = Gen.map
let g = Gen.constant 1
(fun a b c d -> a + b + c + d) <!> g <*> g <*> g <*> g
Also on the topic of applicatives, we should probably add support for the new applicative syntax in F# 5 at some point. |
Indeed. In fact, I didn't realize that those operators are already defined. fsharp-hedgehog/src/Hedgehog/Gen.fs Lines 507 to 510 in 7058b4c
|
I think you mean |
Ah, yes you're correct. It was literally two lines before 😄 |
@TysonMN I've flipped the parameters for |
Yes, those changes look good. Thanks @adam-becker! :) |
This branch has conflicts that must be resolved, then we can merge it. |
@moodmosaic Going to do a quick skim to see if there are other functions that need to be rearranged. Edit: Ready to merge! |
Double check if the Gen.bool <!> not <!> not while the function form would look like Gen.bool |> Gen.map not |> Gen.map not |
I've always seen let y = // Gen<int>
(fun a b -> a + b) // int -> int -> int
<!> Gen.constant 1 // Gen<int -> int>
<*> Gen.constant 2 // Gen<int> I'm not entirely sold on using the operator versions anyways, and I think they should definitely not be marked with I've looked for references, but almost everywhere I looked omitted the Gen.bool |>> not |>> not We can consider adding this operator, but as I said above I think using these operators should be something a user opts in to. Edit: I think the we only have ( $ ) :: (a -> b) -> a -> b
(<$>) :: Functor f => (a -> b) -> f a -> f b
f $ x = f x
f <$> x = fmap f x val (<| ) : (a -> b) -> 'a -> 'b
val (<!>) : (a -> b) -> Gen<'a> -> Gen<'b>
let (<| ) f x = f x
let (<!>) f x = Gen.map f x |
Ok. You have definitely thought about this more than me. I am fibre with whatever you want. I don't use the operators anyway. I also think not auto opening the operators is reasonable. |
Agreed with @adam-becker. Infix operators in F# must be defined per type (unless you do some funky usage of statically resolved type parameter tricks), so using these operators should be only something a user opts in to. |
@moodmosaic I've made the change to opt-in to operators for |
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.
Looks good to me! Massive piece of work. If @TysonMN also agrees, we can merge 🚀
Yep, looks great. Excellent work @adam-becker! :) |
Fixes #265.
The goal is to allow better data flow through the combinators, like: