Search code examples
haskellf#stm

How to write F# stm as >>= pipeline


Can somebody please explain how to write this FSharpx stm as a pipeline?

    stm {
        let! allTops = readTVar tAllTops
        let! thisPlayerTops = mapM removeOtherPlayersScores allTops
        let! markedTops = mapM markAsNonEmpty thisPlayerTops

        return 
            markedTops 
            |> Seq.filter fst 
            |> Seq.map snd
            |> List.ofSeq
    } 

I'm thinking of haskell-like >>= pipelines.

Thanks!

UPDATE: A little bit of clarification in order to avoid the confusion:

I was thinking that one should be able to define the >>= operator in F# in terms of stm.Bind and stm.Return. I tried to do that myself by I got lost.

UPDATE2: After Thomas' answer I post the updated version which I think it looks pretty OK. If I understand correctly, because of lack of type-classes the operator >>= doesn't have the same power as in Haskell.

I agree that it's not idiomatic for F# but it's probably a good exercise.

    readTVar tAllTops
    >>= mapM removeOtherPlayersScores 
    >>= mapM markAsNonEmpty 
    >>= stm.Return >> Seq.filter fst  >> Seq.map snd >> List.ofSeq
    |> atomically

Thanks!


Solution

  • The >>= operator in Haskell is just a symbolic name for the bind operation, so you can define it in F# just as an alias for stm.Bind:

    let (>>=) v f = stm.Bind(v, f)
    

    Using the operator, you could rewrite the code as follows:

    readTVar tAllTops >>= fun allTops ->
    removeOtherPlayersScores allTops >>= fun thisPlayerTops ->
    mapM markAsNonEmpty thisPlayerTops >>= fun markedTops ->
      markedTops 
      |> Seq.filter fst 
      |> Seq.map snd
      |> List.ofSeq
      |> stm.Return
    

    This is certainly an interesting thing and a good way to learn about monads in F# (especially if you are coming from the Haskell background), but it is not an idiomatic style - the idiomatic style in F# is to use the computations explicitly.

    One limitation of this approach (compared to Haskell) is that >>= is not polymorphic over monads, so you're not gaining anything. Also, I think that there is a general consensus that using the computation blocks is more readable (for F# developers)