F # organizacja kodu: typy i moduły

Jak zdecydować, czy pisać funkcję wewnątrz modułu, czy jako statyczny element jakiegoś typu?

Na przykład, w kodzie źródłowym F#, istnieje wiele typów, które są zdefiniowane wraz z równie nazwanym modułem, w następujący sposób:

type MyType = // ...

[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module MyType = // ...

Dlaczego po prostu nie zdefiniujesz operacji jako statycznych członków typu MyType?

Author: Bruno Reis, 2010-02-06

4 answers

Oto kilka uwag na temat technicznych rozróżnień.

Moduły mogą być "otwarte" (o ile nie wymagają wymaganego dostępu). Oznacza to, że jeśli umieścisz funkcje (F i G) w module (M), możesz napisać

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

Podczas gdy metodą statyczną zawsze piszesz

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

Funkcje modułu nie mogą być przeciążone . Funkcje w module są let-bound, a funkcje let-bound nie pozwalają na przeciążenie. Jeśli chcesz być możliwość wywołania obu

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

Musisz użyć member s typu, które działają tylko z wywołaniami "kwalifikowanymi" (np. type.StaticMember(...) lub object.InstanceMember(...)).

(czy są inne różnice? Nie pamiętam.)

Są to główne różnice techniczne, które wpływają na wybór jednego nad drugim.

Dodatkowo istnieje pewna tendencja w środowisku uruchomieniowym F # (FSharp.Rdzeń.dll) używać modułów tylko dla typów specyficznych dla F#(które zazwyczaj nie są używane podczas współpracy z innymi językami. Net) i statyczne metody dla interfejsów API, które są bardziej neutralne językowo. Na przykład wszystkie funkcje z parametrami Currie pojawiają się w modułach (funkcje Currie są nietrywialne do wywołania z innych języków).

 25
Author: Brian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-06 19:18:47

W F# wolę statyczny element na typie niż funkcję w module if ...

  1. muszę zdefiniować typ niezależnie od członu
  2. Element jest funkcjonalnie powiązany z typem, który definiuję
 3
Author: JaredPar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-06 18:40:34

Oprócz innych odpowiedzi istnieje jeszcze jeden przypadek użycia modułów:

Dla typów wartości mogą one pomóc zdefiniować właściwości statyczne, które nie są poddawane ponownej ocenie za każdym razem, gdy są dostępne. na przykład:

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 )
 2
Author: Goswin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-30 15:02:00

Niektóre duże wyróżnienia, które nie były pierwotnie wymienione:

  • Funkcje są wartościami pierwszej klasy W F#, ale statycznymi członkami nie są. Więc możesz pisać objs |> Seq.map Obj.func, ale nie możesz pisać objs |> Seq.map Obj.Member.

  • Funkcje mogą być zwijane, ale członkowie nie mogą.

  • Kompilator wywnioskuje typy automatycznie po wywołaniu funkcji, ale nie po wywołaniu członka. Więc możesz pisać let func obj = obj |> Obj.otherFunc, ale nie możesz pisać let func obj = obj.Member.

Ponieważ członkowie są bardziej ograniczone, zwykle używam funkcji, chyba że wyraźnie chcę wspierać OOP / C#.

 0
Author: brianberns,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-14 21:26:42