公共记录类型的构造函数?

2024-03-18

假设我想要一个记录类型,例如:

type CounterValues = { Values: (int) list; IsCorrupt: bool }

问题是,我想创建一个构造函数,将传递的整数列表转换为一个没有负值的新列表(它们将被 0 替换),并且仅当在构造时发现负值时才具有 IsCorrupt=true 。

这可以用 F# 实现吗?

现在,这就是我所做的,使用属性(但是,呃,它不是很 F#-ish,它每次都会在 getter 处调用 ConvertAllNegativeValuesToZeroes(),所以效率不是很高):

type CounterValues
    (values: (int) list) =

    static member private AnyNegativeValues
        (values: (int) list)
        : bool =
            match values with
            | v::t -> (v < 0) || CounterValues.AnyNegativeValues(t)
            | [] -> false

    static member private ConvertAllNegativeValuesToZeroes
        (values: (int) list)
        : (int) list =
            match values with
            | [] -> []
            | v::t ->
                if (v < 0) then
                    0::CounterValues.ConvertAllNegativeValuesToZeroes(t)
                else
                    v::CounterValues.ConvertAllNegativeValuesToZeroes(t)

    member this.IsCorrupt = CounterValues.AnyNegativeValues(values)

    member this.Values
        with get()
            : (int) list =
                CounterValues.ConvertAllNegativeValuesToZeroes(values)

A F# 中相当惯用的方法是使用签名文件隐藏实施细节 http://fsharpforfunandprofit.com/posts/designing-with-types-single-case-dus,但一如既往,这涉及到权衡。

想象一下您已经这样定义了模型:

module MyDomainModel

type CounterValues = { Values : int list; IsCorrupt : bool }

let createCounterValues values =
    {
        Values = values |> List.map (max 0)
        IsCorrupt = values |> List.exists (fun x -> x < 0)
    }

let values cv = cv.Values

let isCorrupt cv = cv.IsCorrupt

请注意,除了create检查输入的函数,该模块还包含以下访问器函数Values and IsCorrupt。这是必要的,因为下一步。

到目前为止,定义在MyDomainModel模块是公共的。

但是,现在您添加一个签名文件 (a .fsi file) before the .fs文件包含MyDomainModel。在签名文件中,您只放置想要发布到外界的内容:

module MyDomainModel

type CounterValues
val createCounterValues : values : int list -> CounterValues
val values : counterValues : CounterValues -> int list
val isCorrupt : counterValues : CounterValues -> bool

请注意,声明的模块名称是相同的,但类型和函数仅在抽象中声明。

Because CounterValues被定义为一种类型,但没有任何特定的结构,任何客户端都无法创建它的实例。换句话说,这不能编译:

module Client

open MyDomainModel

let cv = { Values = [1; 2]; IsCorrupt = true }

编译器抱怨“记录标签‘Values’未定义”。

另一方面,客户端仍然可以访问签名文件定义的功能。这编译:

module Client

let cv = MyDomainModel.createCounterValues [1; 2]
let v = cv |> MyDomainModel.values
let c = cv |> MyDomainModel.isCorrupt

以下是 FSI 的一些示例:

> createCounterValues [1; -1; 2] |> values;;
val it : int list = [1; 0; 2]

> createCounterValues [1; -1; 2] |> isCorrupt;;
val it : bool = true

> createCounterValues [1; 2] |> isCorrupt;;
val it : bool = false

> createCounterValues [1; 2] |> values;;
val it : int list = [1; 2]

缺点之一是保留签名文件会产生开销(.fsi)和实现文件(.fs) 同步中。

另一个缺点是客户端无法自动访问记录的命名元素。相反,您必须定义和维护访问器函数,例如values and isCorrupt.


尽管如此,这并不是 F# 中最常见的方法。更常见的方法是提供必要的函数来动态计算此类问题的答案:

module Alternative

let replaceNegatives = List.map (max 0)

let isCorrupt = List.exists (fun x -> x < 0)

如果列表不太大,则动态计算此类答案所涉及的性能开销可能小到足以忽略(或者可以通过记忆来解决)。

以下是一些使用示例:

> [1; -2; 3] |> replaceNegatives;;
val it : int list = [1; 0; 3]

> [1; -2; 3] |> isCorrupt;;
val it : bool = true

> [1; 2; 3] |> replaceNegatives;;
val it : int list = [1; 2; 3]

> [1; 2; 3] |> isCorrupt;;
val it : bool = false
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

公共记录类型的构造函数? 的相关文章

  • C++ 使用枚举调用基类构造函数

    是否可以将值和常量枚举传递给类的基本构造函数 例如 enum CarBrand Volkswagen Ferrari Bugatti class Car public Car int horsePower CarBrand brand th
  • 为什么 Haskell 类型签名声明有多个箭头?

    抱歉 这句话措辞不好 但很难描述 我想我会跳到这个例子 add Integer gt Integer gt Integer add x y x y 为什么 Integer gt Integer gt Integer 代替 Integer I
  • 在 C# 中将字符串转换为类型[重复]

    这个问题在这里已经有答案了 如果我收到一个包含类名称的字符串 并且我想将该字符串转换为真实类型 字符串中的类型 我该怎么做 I tried Type GetType System Int32 例如 它似乎有效 但是当我尝试使用自己的对象时
  • Async.TryCancelled 不适用于 Async.RunSynchronously

    我尝试创建一个根据用户交互更新 UI 的代理 如果用户单击按钮 则应刷新 GUI 模型的准备需要很长时间 因此希望如果用户单击其他按钮 则取消准备并开始新的准备 到目前为止我所拥有的 open System Threading type p
  • 运营商部分应用

    如果我想在字符末尾添加一个空格以返回列表 如果我不传递任何参数 我将如何通过部分应用程序来完成此操作 还有类型是 space Char gt Char 由于使用 和 运算符出现 解析错误 我在末尾添加空格时遇到问题 到目前为止我所拥有的是
  • 如何在 C++ 中将方法结果作为参数传递给基类构造函数?

    我试图实现这样的目标 class Base public Base string S class Derived Base public int foo string bar return stringof foo actually som
  • 要统一的类型变量出现在类型中

    我有一个函数可以从两个列表重建一棵树 我返回所有分支的列表 但收到一个我不明白的错误 但我认为这与返回类型有关 错误是这样的 Can t unify a with a list Type variable to be unified occ
  • Oracle BLOB 与 VARCHAR

    我需要在表的一列中存储一个 大 SQL 查询 我想使用BLOB场地 需要明确的是 我想存储查询 而不是其结果 最好使用什么 BLOB or a VARCHAR 或者也许还有别的什么 另一种选择是 CLOB 对于文本数据 使用 CLOB 比使
  • F# 参数传递

    我一直认为 F 有两种不同的方式来传递参数 柯里化风格和元组风格 这实际上是正确的吗 是不是很简单一种风格 柯里化风格和参数可以是简单值或元组 e g someFunc a b 这不是一个函数吗one咖喱风格的参数恰好是一个元组 因此允许我
  • 如何在插件场景中实现程序集绑定重定向?

    我有一个plugin P延伸和application A NET40 我无法控制 P 程序集 NET40 有一个shared dependency D NET35 P和D都依赖于FSharp Core 但版本不同 P是针对FSharp Co
  • 何时在 F# 中使用区分联合与记录类型

    在继续讨论复杂的示例之前 我试图先弄清楚 F 的基础知识 我正在学习的材料介绍了区分联合和记录类型 我已经审阅了两者的材料 但我仍然不清楚为什么我们要使用其中之一而不是另一个 我创建的大多数玩具示例似乎都可以在两者中实现 记录似乎非常接近我
  • 像数组一样初始化类对象

    我正在为学校项目创建一个自定义向量类 我希望能够像这样初始化它 vector x 2 3 4 5 C 有什么办法可以做到这一点吗 这是我的班级的标题 class vector private int vsize int valloc dou
  • 如何在 F# 中将对象转换为泛型类型列表

    在下面的代码片段中 我的目的是将 System Object 可能是 FSharpList 转换为它所持有的任何泛型类型的列表 match o with list lt gt gt addChildList o gt list lt gt
  • 使用 postgresql DB 存储 NULL 值需要多少磁盘空间?

    假设我的表上有一列定义了以下内容 MyColumn smallint NULL 存储 0 1 或其他值等值应该需要 2 个字节 1 但是如果我将 MyColumn 设置为NULL 需要多少空间 需要0字节吗 出于管理目的或每列 行是否有一些
  • `ImmutableSortedSet` 和 fsharp `Set` 有什么区别?

    BCL引入了一组Immutable Collections http blogs msdn com b bclteam archive 2012 12 18 preview of immutable collections released
  • mysql 中 int(11) 列的大小是多少(以字节为单位)?

    柱子的尺寸是多少int 11 在mysql中以字节为单位 该列中可以存储的最大值 An INT无论指定什么长度 都将始终为 4 个字节 TINYINT 1 字节 8 位 SMALLINT 2 字节 16 位 MEDIUMINT 3 字节 2
  • 浮点型、双精度型和十进制最大值与大小的关系[重复]

    这个问题在这里已经有答案了 我在 C 中遇到了这些数据类型的大小和最大值的令人困惑的模式 在使用 Marshal SizeOf 比较这些大小时 我发现了以下结果 Float 4 bytes Double 8 bytes Decimal 16
  • 防止被 0 除的 Typescript 类型

    我正在使用打字稿创建一个用于培训目的的计算系统 但在除法过程中出现打字错误 您知道如何解决吗 type Variable value number resolve gt number type NoZeroVariable value Om
  • Visual Studio 2010 基类扩展编译器错误

    我有一个 C 类 提供一些简单的类和一些基类扩展 例如这个 public static Boolean ToBooleanOrDefault this String s Boolean Default return ToBooleanOrD
  • 为什么 Python 布尔值占用超过一个字节?

    显然 Python 中整数占用 24 个字节 我可以理解 它这样做是因为代表无限数字的额外花哨 然而 布尔数据类型看起来也花费了高达 24 个字节 尽管它只能表示两个可能值之一 为什么 除了 1 位表示之外 还可能需要存储哪些额外数据Tru

随机推荐