F#中自然数的类型级编码

时间:2014-11-19 14:11:20

标签: types f# inline type-level-computation

我试图将自然数编码为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吗?

1 个答案:

答案 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,您也可以获得结构相等性,因此在此解决方案中,您可以同时键入(在编译时)和值(在运行时)相等。

通过使用内联,将在编译时解析要调用的方法。