F# code organization: types & modules

后端 未结 4 1907
抹茶落季
抹茶落季 2020-12-24 02:52

How do you decide between writing a function inside a module or as a static member of some type?

For example, in the source code of F#, there are lots of types that

相关标签:
4条回答
  • 2020-12-24 03:05

    In addition to the other answers there is one more case to use Modules:

    For value types they can help to define static properties that do not get re-evaluated every time they are accessed. for example:

    type [<Struct>] Point =
        val x:float
        val y:float
        new (x,y) = {x=x;y=y}
    
        static member specialPoint1 = // sqrt is computed every time the property is accessed
            Point (sqrt 0.5 , sqrt 0.5 )
    
    [<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
    module Point = 
    
        let specialPoint2 = // sqrt is computed only once when the Module is opened
            Point (sqrt 0.5 , sqrt 0.5 )
    
    0 讨论(0)
  • 2020-12-24 03:14

    Some big distinctions that weren't originally mentioned:

    • Functions are first class values in F#, but static members are not. So you can write objs |> Seq.map Obj.func but you can't write objs |> Seq.map Obj.Member.

    • Functions can be curried, but members cannot.

    • The compiler will infer types automatically when you call a function, but not when you invoke a member. So you can write let func obj = obj |> Obj.otherFunc but you can't write let func obj = obj.Member.

    Since members are more restricted, I usually use functions unless I explicitly want to support OOP/C#.

    0 讨论(0)
  • 2020-12-24 03:16

    Here are some notes about the technical distinctions.

    Modules can be 'open'ed (unless they have RequireQualifiedAccessAttribute). That is, if you put functions (F and G) in a module (M), then you can write

    open M
    ... F x ... G x ...
    

    whereas with a static method, you'd always write

    ... M.F x ... M.G x ...
    

    Module functions cannot be overloaded. Functions in a module are let-bound, and let-bound functions do not permit overloading. If you want to be able to call both

    X.F(someInt)
    X.F(someInt, someString)
    

    you must use members of a type, which only work with 'qualified' calls (e.g. type.StaticMember(...) or object.InstanceMember(...)).

    (Are there other differences? I can't recall.)

    Those are the main technical differences that influence the choice of one over the other.

    Additionally, there is some tendency in the F# runtime (FSharp.Core.dll) to use modules only for F#-specific types (that are typically not used when doing interop with other .Net languages) and static methods for APIs that are more language-neutral. For example, all the functions with curried parameters appear in modules (curried functions are non-trivial to call from other languages).

    0 讨论(0)
  • 2020-12-24 03:30

    In F# I prefer a static member on a type over a function in a module if ...

    1. I have to define the type irrespective of the member
    2. The member is functionally related to the type I'm defining
    0 讨论(0)
提交回复
热议问题