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,此函数只能按预期工作。
这引发了我的几个问题:
- 有没有办法从泛型(数字)类型中获取中性元素(零)?
- 如何表达限制,例如“仅签名号码”?
- 有没有办法在 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/