Types F中自然数的类型级编码#
我试图将自然数编码为F#中的一种类型,以便能够在编译时而不是运行时检查等式。我能想出的最好办法就是Types F中自然数的类型级编码#,types,f#,inline,type-level-computation,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>
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)
使用
成员_uuu.AsInt=1+prev.AsInt
TNat型=
静态成员zero=Z():>Nat
静态成员成功(上一个:Nat>
静态成员1=TNat.succ(TNat.zero)
静态成员2=TNat.succ(TNat.one)
我不确定我对代码是否满意。是否可以用我忽略的更好(或更容易)的方式来完成
我可以确保
AsInt
是在编译时计算的吗?在您的代码中,如果您尝试:
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
类型Z=Z,带有
静态成员(!!)Z=0
类型F#type系统允许您执行一点类型级别的编程,但不是很多-因此我认为这种方法不会很好地工作(如果您想将其用于实际的事情).您尝试这样做的背景是什么?我想创建一个工具来计算一系列值的第n个矩,并能够组合部分结果。我认为在编译时检查我不能组合不同的矩会很好。计算的矩在编译时是固定的,高阶矩是固定的最不需要的。除此之外还有好奇心:-)这听起来确实是一个非常有趣的用例。我想你可以(用你所拥有的)让它工作起来,虽然语法不会更漂亮。您也可以为类似的东西编写类型提供程序,例如,时刻
——这也扩展了类型系统,但可能会更好。请参阅,谢谢您的提示。事实上,考虑到更好的语法,我想我更喜欢类型提供程序,并会尝试它们。谢谢。不是(TNat.two=TNat.succ(TNat.one))
确实很难看。我想我需要一个接口来调用(!!)
,但在您的版本中,我可以简单地内联以获得静态成员约束,即让内联asInt(n:'T)=!!n
。是的,我使用一个中间运算符让编译器自动推断静态约束。然后,当我定义nice asInt函数时,约束会被传播。你也可以去掉该运算符,手工编写约束。我非常喜欢这个解决方案,但是有没有办法有效地包装S
和Z
返回到一个NatNum
类型,就像一个有区别的联合?当然,只需更改(!!)
的实现即可返回DU。