f# - 如何对通用计算函数使用 f# 约束?

标签 f# inline type-constraints

type Point<'t> =
    val X : 't
    val Y : 't
    new(x : 't,y : 't) = { X = x; Y = y }

let clampedSubtract (p1:Point<_>) (p2:Point<_>) =
    Point( max (p2.X - p1.X) 0, max (p2.Y - p1.Y) 0 )

如果您查看上面的代码,您会注意到,该函数的实现并没有像它应该的那样通用。

首先,在 max 表达式中使用 0 将类型限制为 int。但它应该是任何类型的类型 Point<'t>有和没有Point<int> .

但更重要的是,如果将签名类型用于 `t,此函数只能按预期工作。

这引发了我的几个问题:

  1. 有没有办法从泛型(数字)类型中获取中性元素(零)?
  2. 如何表达限制,例如“仅签名号码”?
  3. 有没有办法在 F# 中扩展类型约束系统?

提前致谢。

最佳答案

已回答的第一个问题的解决方案是将内联函数与 GenericZero 一起使用,仅此而已。

关于signed限制,其实有一种简单的方法可以限制为signed类型。在某处使用仅为签名类型定义的通用一元否定:

let inline clampedSubtract (p1:Point<_>) (p2:Point<_>) =
    let zero = LanguagePrimitives.GenericZero
    Point( max (p2.X + -p1.X) zero, max (p2.Y + -p1.Y) zero )

let result1 = clampedSubtract (Point(4  , 5  )) (Point(4  , 5  ))
let result2 = clampedSubtract (Point(4y , 5y )) (Point(4y , 5y ))
let result3 = clampedSubtract (Point(4uy, 5uy)) (Point(4uy, 5uy)) // doesn't compile

一般来说,如果你想将任何泛型函数限制为有符号类型,你可以定义这个函数:

let inline whenSigned x = ignore (-x)

let inline clampedSubtract (p1:Point<_>) (p2:Point<_>) =
    whenSigned p1.X
    let zero = LanguagePrimitives.GenericZero
    Point( max (p2.X - p1.X) zero, max (p2.Y - p1.Y) zero )

最后,关于您的第三个问题,我不太清楚扩展类型系统是什么意思。您可以自己创建静态约束,从这个意义上说,系统已经是可扩展的。

我前段时间做了一个项目来模拟一些Haskell类型,该项目的部分代码仍在FsControl中的一个模块中。在那里,您可以了解在这些限制条件下您可以玩到什么水平。

关于f# - 如何对通用计算函数使用 f# 约束?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28631439/

相关文章:

performance - 整数运算性能 32 位与 64 位

带有 <"string"的 F# 构造函数,str>

security - 使用正确的文件名在浏览器中安全下载文件

c - 在 C99 中,我可以在不先将其分配给变量的情况下使用返回值吗?

javascript - 如何执行 "inline solution"&lt;input type ="text"> 只允许数字,否则它也会发出警报?

c# - 将枚举值作为参数的通用 C# 方法

list - 反转列表列表

.net - 了解 F# 静态成员约束(构造小于通用警告)

haskell - 将类型类约束应用于另一个类型类的内部类型

F# 使用累加器,仍然出现堆栈溢出异常