是否可以这样表达:
type id = int > 0
我知道它不可能静态地做,因为这意味着 F# 有依赖类型。在 C# 中,我习惯于用代码契约来做这种事情并获得运行时强制。我在这里寻找类似的东西。
谢谢
编辑:感谢您提供各种利弊的答案。目前我只使用 F# 的一个小子集,它是 ocaml 核心的一个子集,可以很容易地进行编程证明。所以不上课。
是否可以这样表达:
type id = int > 0
我知道它不可能静态地做,因为这意味着 F# 有依赖类型。在 C# 中,我习惯于用代码契约来做这种事情并获得运行时强制。我在这里寻找类似的东西。
谢谢
编辑:感谢您提供各种利弊的答案。目前我只使用 F# 的一个小子集,它是 ocaml 核心的一个子集,可以很容易地进行编程证明。所以不上课。
与其他人所说的相反,如果我正确理解您的问题,我建议不要在这里使用类。
由于值是不可变的,我们只需要应用一次约束。任何包装类都将是开销和负载 GC。相反,一个简单的函数将完成这项工作:
let inline constrained predicate errormessage value =
if not (predicate value)
then invalidArg "value" errormessage
else value
let positive =
constrained (fun x -> x > 0) "Value must be positive"
let int1 = positive 5 // OK
let int2 = positive -3 // ArgumentException
您可以对其他类型执行相同操作:
let mustBeLong =
constrained (fun (x:string) -> x.Length > 3) "String must be long"
let str1 = mustBeLong "foobar" // OK
let str2 = mustBeLong "baz" // ArgumentException
在结构中使用相同的:
type Point2D =
struct
val X: int
val Y: int
new(x: int, y: int) = { X = positive x; Y = positive y }
end
let point1 = Point2D(5, 3) // OK
let point2 = Point2D(5, -2) // ArgumentException
将其定义为联合类型:
type Id = Id of int
并使用另一个函数隐藏构造函数:
let Id n =
assert(n > 0)
Id n
在 F# 中,您必须求助于类并检查构造函数中的参数。其他类型(例如可区分联合、记录和结构)具有隐式构造函数,您无法轻易更改这些构造函数。
type Id(i: int) =
do if i <= 0 then
invalidArg "i" "the argument has to be a positive integer"
member x.Value = i
模式匹配不能很好地与类一起使用。您可以使用活动模式解决问题:
let (|Id|) (id: Id) = id.Value
let id = Id(1)
match id with
| Id 1 -> printfn "matched"
| _ -> printfn "unmatched"
You could create a generic class like so:
type verify<'t>(t:'t,cond) =
let mutable tval = t
let _verify v = if not (cond v) then failwith "bad argument"
do _verify tval
member x.get() = tval
member x.set v =
_verify v
tval <- v
then you can use it with
verify(1,fun t -> t>0)
using .set
will recheck the condition.