F#: Advantages of converting top-level functions to member methods?

Posted by J Cooper on Stack Overflow See other posts from Stack Overflow or by J Cooper
Published on 2010-06-06T00:20:28Z Indexed on 2010/06/06 0:22 UTC
Read the original article Hit count: 559

Filed under:
|
|
|

Earlier I requested some feedback on my first F# project. Before closing the question because the scope was too large, someone was kind enough to look it over and leave some feedback.

One of the things they mentioned was pointing out that I had a number of regular functions that could be converted to be methods on my datatypes. Dutifully I went through changing things like

let getDecisions hand =
    let (/=/) card1 card2 = matchValue card1 = matchValue card2
    let canSplit() = 
        let isPair() =
            match hand.Cards with
            | card1 :: card2 :: [] when card1 /=/ card2 -> true
            | _ -> false
        not (hasState Splitting hand) && isPair()
    let decisions = [Hit; Stand]
    let split = if canSplit() then [Split] else []
    let doubleDown = if hasState Initial hand then [DoubleDown] else []
    decisions @ split @ doubleDown

to this:

type Hand
// ...stuff...
member hand.GetDecisions =
    let (/=/) (c1 : Card) (c2 : Card) = c1.MatchValue = c2.MatchValue
    let canSplit() = 
        let isPair() =
            match hand.Cards with
            | card1 :: card2 :: [] when card1 /=/ card2 -> true
            | _ -> false
        not (hand.HasState Splitting) && isPair()
    let decisions = [Hit; Stand]
    let split = if canSplit() then [Split] else []
    let doubleDown = if hand.HasState Initial then [DoubleDown] else []
    decisions @ split @ doubleDown

Now, I don't doubt I'm an idiot, but other than (I'm guessing) making C# interop easier, what did that gain me? Specifically, I found a couple *dis*advantages, not counting the extra work of conversion (which I won't count, since I could have done it this way in the first place, I suppose, although that would have made using F# Interactive more of a pain). For one thing, I'm now no longer able to work with function "pipelining" easily. I had to go and change some |> chained |> calls to (some |> chained).Calls etc. Also, it seemed to make my type system dumber--whereas with my original version, my program needed no type annotations, after converting largely to member methods, I got a bunch of errors about lookups being indeterminate at that point, and I had to go and add type annotations (an example of this is in the (/=/) above).

I hope I haven't come off too dubious, as I appreciate the advice I received, and writing idiomatic code is important to me. I'm just curious why the idiom is the way it is :)

Thanks!

© Stack Overflow or respective owner

Related posts about beginner

Related posts about F#