我试图将自然数编码为F#中的类型,以便能够在编译时检查相等而不是运行时。我能想到的最好的是
type Nat<'T> =
abstract member AsInt : int
type Z() =
interface Nat<Z> with
member __.AsInt = 0
type S<'P>(prev : Nat<'P>) =
interface Nat<S<'P>> with
member __.AsInt = 1 + prev.AsInt
type TNat =
static member zero = Z() :> Nat<Z>
static member succ (prev : Nat<'P>) = S(prev) :> Nat<S<'P>>
static member one = TNat.succ(TNat.zero)
static member two = TNat.succ(TNat.one)
我不确定我是否对代码感到满意。它能以更好(或更容易)的方式完成吗?
我可以确保在编译时计算AsInt
吗?
答案 0 :(得分:6)
在您的代码中,如果您尝试:
TNat.two = TNat.succ(TNat.one)
会产生错误。
这是一个没有接口的替代实现:
type Z = Z with
static member (!!) Z = 0
type S<'a> = S of 'a with
static member inline (!!) (S a) = !!a + 1
let inline asInt x = !! x
let one = S Z
let two = S one
通过使用Discriminated Unions,您也可以获得结构相等性,因此在此解决方案中,您可以同时键入(在编译时)和值(在运行时)相等。
通过使用内联,将在编译时解析要调用的方法。