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

Hedgehog bind functions are backwards #265

Closed
ghost opened this issue Jan 12, 2021 · 4 comments · Fixed by #266
Closed

Hedgehog bind functions are backwards #265

ghost opened this issue Jan 12, 2021 · 4 comments · Fixed by #266
Milestone

Comments

@ghost
Copy link

ghost commented Jan 12, 2021

Axiomatically, the bind function in F# has a different parameter order than the Bind method in a computation expression. This is well established, and Hedgehog does it wrong.

module Gen =
    val bind : Gen<'a> -> ('a -> Gen<'b>) -> Gen<'b>

module Property =
    val bind : Property<'a> -> ('a -> Property<'b>) -> Property<'b>

module Random =
    val bind : Random<'a> -> ('a -> Random<'b>) -> Random<'b>

module Tree =
    val bind : Tree<'a> -> ('a -> Tree<'b>) -> Tree<'b>

Other modules in F# are consistent on this.

module Option =
    val bind : ('a -> Option<'b>) -> Option<'a> -> Option<'b>

module Result =
    val bind : ('a -> Result<'b, 'error>) -> Result<'a, 'error> -> Result<'b, 'error>

module Seq =
    val collect : ('a -> seq<'b>) -> seq<'a> -> seq<'b>

module Array =
    val collect : ('a -> Array<'b>) -> Array<'a> -> Array<'b>

module List =
    val collect : ('a -> List<'b>) -> List<'a> -> List<'b>

It's done this way to allow simple chaining, which is how I noticed this.

@ghost ghost changed the title Gen.bind is backwards Hedgehog bind functions are backwards Jan 12, 2021
@TysonMN
Copy link
Member

TysonMN commented Jan 12, 2021

I agree with @adam-becker.

The signature of the bind function named bind for a monad M<_> should be

let bind (f: 'a -> M<'b>) (ma: M<'a>) : M<'b> =

In contrast, the signature of the bind operator denoted by >>= (which doesn't exist in fsharp-hedgehog) should be

let (>>=) (ma: M<'a>) (f: 'a -> M<'b>) : M<'b> =

These are "the flip" of each other: i.e. flip bind = (>>=). Here is the reason for this. Consider

a >>= b

and

a |> bind b

The arguments to >>= are given in the order a then b. In contrast, the arguments to bind are given in the order b then a.

@moodmosaic
Copy link
Member

Agreed, bind right now can add cognitive overhead to F# developers that aren't coming from Haskell. Good point. 👍

@TysonMN
Copy link
Member

TysonMN commented Jan 13, 2021

...the bind operator denoted by >>= (which doesn't exist in fsharp-hedgehog)...

Another idea (@adam-becker) is to add this operator.

@ghost
Copy link
Author

ghost commented Jan 14, 2021

@TysonMN I added the operator, though suggestions like this fit better on the PR :)

@ghost ghost added this to the 0.10.0 milestone Jan 31, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants