F# - 合并模块?

发布于 2024-11-02 23:48:42 字数 2640 浏览 0 评论 0原文

我目前正在为 F# 开发一个实体框架代码优先包装器,我一直在想是否应该将所有模块合并为一个。

看看这个:

module ManyNavProperty =
    let withMany (cfg:ManyNavPropertyInfo<'a,'b>) = cfg.WithMany()
    let withSeq expr (cfg:ManyNavPropertyInfo<'a,'b>) = cfg.WithSeq expr
    let withList expr (cfg:ManyNavPropertyInfo<'a,'b>) = cfg.WithList expr
    let withArray expr (cfg:ManyNavPropertyInfo<'a,'b>) = cfg.WithArray expr
    let withOptional (cfg:ManyNavPropertyInfo<'a,'b>) = cfg.WithOptional()
    let withOptionalProperty expr (cfg:ManyNavPropertyInfo<'a,'b>) = cfg.WithOptional expr
    let withRequired (cfg:ManyNavPropertyInfo<'a,'b>) = cfg.WithRequired()
    let withRequiredProperty expr (cfg:ManyNavPropertyInfo<'a,'b>) = cfg.WithRequiredProperty expr

module DependentNavProperty =
    let hasForeignKey expr (cfg:DependentNavPropertyInfo<'a>) = cfg.HasForeignKey expr

module CascadableNavProperty =
    let willCascadeOnDelete b (cfg:CascadableNavPropertyInfo) = cfg.WillCascadeOnDelete b

module EF =
    let entity<'a when 'a : not struct> (cfg:DbModelBuilder) = EntityInfo<'a>(cfg.Entity<'a>())
    let hasKey expr (cfg:EntityInfo<'a>) = cfg.HasKey expr
    let hasSeq expr (cfg:EntityInfo<'a>) = cfg.HasSeq expr
    let hasList expr (cfg:EntityInfo<'a>) = cfg.HasList expr 
    let hasArray expr (cfg:EntityInfo<'a>) = cfg.HasArray expr
    let hasOptional expr (cfg:EntityInfo<'a>) = cfg.HasOptional expr
    let hasRequired expr (cfg:EntityInfo<'a>) = cfg.HasRequried expr
    let toTable s (cfg:EntityInfo<'a>) = cfg.ToTable s

这需要我调用这样的代码:

override x.OnModelCreating (mb:DbModelBuilder) =
    let finished = ignore
    let entity = EF.entity<Author> mb

    entity
    |> EF.hasSeq <@ fun z -> z.Books @>
        |> ManyNavProperty.withRequiredProperty <@ fun z -> z.Author @>
            |> DependentNavProperty.hasForeignKey <@ fun z -> z.AuthorId @>
                |> CascadableNavProperty.willCascadeOnDelete true
    |> finished

使用这么多模块会让用户感到困惑吗? - 我应该将它们全部放入一个模块中,还是会破坏用户的概览?

所有函数都放置在同一模块中的示例:

override x.OnModelCreating (mb:DbModelBuilder) =
    let finished = ignore
    let entity = EF.entity<Author> mb

    entity
    |> EF.hasSeq <@ fun z -> z.Books @>
        |> EF.withRequiredProperty <@ fun z -> z.Author @>
            |> EF.hasForeignKey <@ fun z -> z.AuthorId @>
                |> EF.willCascadeOnDelete true
    |> finished

I'm at the moment working on a Entity Framework Code First Wrapper for F#, and I've been wondering whether I should merge all my modules into just one.

Take a look at this:

module ManyNavProperty =
    let withMany (cfg:ManyNavPropertyInfo<'a,'b>) = cfg.WithMany()
    let withSeq expr (cfg:ManyNavPropertyInfo<'a,'b>) = cfg.WithSeq expr
    let withList expr (cfg:ManyNavPropertyInfo<'a,'b>) = cfg.WithList expr
    let withArray expr (cfg:ManyNavPropertyInfo<'a,'b>) = cfg.WithArray expr
    let withOptional (cfg:ManyNavPropertyInfo<'a,'b>) = cfg.WithOptional()
    let withOptionalProperty expr (cfg:ManyNavPropertyInfo<'a,'b>) = cfg.WithOptional expr
    let withRequired (cfg:ManyNavPropertyInfo<'a,'b>) = cfg.WithRequired()
    let withRequiredProperty expr (cfg:ManyNavPropertyInfo<'a,'b>) = cfg.WithRequiredProperty expr

module DependentNavProperty =
    let hasForeignKey expr (cfg:DependentNavPropertyInfo<'a>) = cfg.HasForeignKey expr

module CascadableNavProperty =
    let willCascadeOnDelete b (cfg:CascadableNavPropertyInfo) = cfg.WillCascadeOnDelete b

module EF =
    let entity<'a when 'a : not struct> (cfg:DbModelBuilder) = EntityInfo<'a>(cfg.Entity<'a>())
    let hasKey expr (cfg:EntityInfo<'a>) = cfg.HasKey expr
    let hasSeq expr (cfg:EntityInfo<'a>) = cfg.HasSeq expr
    let hasList expr (cfg:EntityInfo<'a>) = cfg.HasList expr 
    let hasArray expr (cfg:EntityInfo<'a>) = cfg.HasArray expr
    let hasOptional expr (cfg:EntityInfo<'a>) = cfg.HasOptional expr
    let hasRequired expr (cfg:EntityInfo<'a>) = cfg.HasRequried expr
    let toTable s (cfg:EntityInfo<'a>) = cfg.ToTable s

that would require me to call the code like:

override x.OnModelCreating (mb:DbModelBuilder) =
    let finished = ignore
    let entity = EF.entity<Author> mb

    entity
    |> EF.hasSeq <@ fun z -> z.Books @>
        |> ManyNavProperty.withRequiredProperty <@ fun z -> z.Author @>
            |> DependentNavProperty.hasForeignKey <@ fun z -> z.AuthorId @>
                |> CascadableNavProperty.willCascadeOnDelete true
    |> finished

Is the use of so many modules confusing for the user? - Should I place them all into one module, or will that destroy the overview for the user?

An example where all functions are placed in same Module:

override x.OnModelCreating (mb:DbModelBuilder) =
    let finished = ignore
    let entity = EF.entity<Author> mb

    entity
    |> EF.hasSeq <@ fun z -> z.Books @>
        |> EF.withRequiredProperty <@ fun z -> z.Author @>
            |> EF.hasForeignKey <@ fun z -> z.AuthorId @>
                |> EF.willCascadeOnDelete true
    |> finished

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

三寸金莲 2024-11-09 23:48:42

这是一个棘手的设计问题。

通常,F# 库倾向于将与类型一起使用的函数(例如 listseq)分组到名称与类型相同的单独模块中(例如List.xyzSeq.xyz)。这对于常见类型非常有效,因为用户学习如何查找函数。

然而,对于不太常见的类型(例如您自己的库),发现这些模块可能有点困难(特别是如果类型不是显式创建的(而是作为某些调用的结果获得的)。拥有一个模块名称,然后使用 . 来探索它是非常强大的。

我可能会建议使用嵌套模块:

module EF =
  // common functions
  module Cascadable = 
    // CascadableNavProperty functions
  module Many = 
    // etc.

然后用户可以从 EF 开始找到所有内容。喜欢:

entity
|> EF.hasSeq <@ fun z -> z.Books @>
  |> EF.Many.withRequiredProperty <@ fun z -> z.Author @>
    |> EF.Dependent.hasForeignKey <@ fun z -> z.AuthorId @>
      |> EF.Cascadable.willCascadeOnDelete true
|> finished

This is a tricky design question.

Generally, F# libraries tend to group functions that work with a type (e.g. list<T> or seq<T>) in a separate module with the name same as the type (e.g. List.xyz and Seq.xyz). This works well for common types, because the users learn how to find the functions.

However, for less common types (e.g. your own library), it may be a bit difficult to discover these modules (especially if the type is not created explicitly (but is obtained as a result of some call). Having one module name and then use . to explore it is quite powerful.

I would probably suggest using nested modules. Something like:

module EF =
  // common functions
  module Cascadable = 
    // CascadableNavProperty functions
  module Many = 
    // etc.

The users could then find everything by starting with EF. They'd write something like:

entity
|> EF.hasSeq <@ fun z -> z.Books @>
  |> EF.Many.withRequiredProperty <@ fun z -> z.Author @>
    |> EF.Dependent.hasForeignKey <@ fun z -> z.AuthorId @>
      |> EF.Cascadable.willCascadeOnDelete true
|> finished
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文