我正在玩F#的类型推导者。试图让类型级自然数工作。
这是我设法开始工作的部分
type Zero = Zero
type Succ<'a> = None
type True = True
type False = False
type IsZero =
| IsZero
static member instance (IsZero, _ : Succ<'a>, _) = fun () -> False
static member instance (IsZero, _ : Zero, _) = fun () -> True
module TypeArithmetic =
let inline zero x = (Inline.instance (IsZero, x) : unit -> 'a)()
let dec (_ : Succ<'a>) = Unchecked.defaultof<'a>
let inc (_ : 'a) = Unchecked.defaultof<Succ<'a>>
整个instance
部分与使FsControl成为可能的hack相同。这个file也是我项目的一部分。
到目前为止这是有效的。我可以做像
这样的事情let a = inc Zero |> inc |> inc |> inc |> dec |> dec |> dec
let b = dec a
let x = zero a
let y = zero b
x和y分别被正确推断为False和True(推断为Succ,b为零)。
现在是棘手的部分。我想创建函数add
。
它需要能够同时使用Succ和Zero,所以我需要使用重载hack来使其工作。
type Add =
| Add
static member instance (Add, _ : Zero, _ : Zero, _) = fun () -> Zero
static member instance (Add, x : Succ<'a>, _ : Zero, _) = fun () -> x
static member instance (Add, _ : Zero, y : Succ<'a>, _) = fun () -> y
static member instance (Add, _ : Succ<'a>, _ : Succ<'b>, _) =
fun () -> Inline.instance(Add, Unchecked.defaultof<Succ<Succ<'a>>>, Unchecked.defaultof<'b>) ()
据我所知,这应该有效。不应该吗?但它并没有。我在Inline.instance
电话上收到错误消息,说明在此之前给出的信息无法解决歧义。我有点理解,因为我没有在内联函数中尝试解析为具体类型,但它还没有。但我仍然觉得我应该能够以某种方式使它发挥作用。
有没有办法让它发挥作用?
答案 0 :(得分:2)
问题是只有一个重载匹配。
您不需要超过两个,您可以添加Zero案例和将循环的案例,顺便说一下,应该按照评论中的说明内联标记:
type Add =
| Add
static member instance (Add, _ :Zero , y , _) = fun () -> y
static member inline instance (Add, _ :Succ<'a>, _:'b, _) = fun () ->
Inline.instance(Add, Unchecked.defaultof<'a>, Unchecked.defaultof<Succ<'b>>) ()
let inline add x y = Inline.instance (Add, x, y)()
但是还有另外一个问题,在第二次超载时它会默认为零,从第一次过载推断出来。
解决此问题的一个技巧是添加虚拟重载:
type Add =
| Add
static member instance (Add, _ :Add , y , _) = fun () -> y
static member instance (Add, _ :Zero , y , _) = fun () -> y
static member inline instance (Add, _ :Succ<'a> ,_:'b, _) = fun () ->
Inline.instance(Add, Unchecked.defaultof<'a>, Unchecked.defaultof<Succ<'b>>) ()
let inline add x y = Inline.instance (Add, x, y)()
这样它就不会默认为零,因为它无法在编译时推断出来。
前段时间我也使用重载运算符和模式匹配来做implementation of type level numbers。
<强>更新强>
你不需要第二个参数是多态的,这也可以做到这一点:
type Add =
| Add
static member instance (Add, _ :Add , _) = id
static member instance (Add, _ :Zero , _) = id
static member inline instance (Add, _ :Succ<'a>, _) = fun (_:'b) ->
Inline.instance(Add, Unchecked.defaultof<'a>) Unchecked.defaultof<Succ<'b>>
您的实现与我所做的之间存在一些差异(请参阅链接),但我不会使用内联帮助程序,至少在FsControl中定义,因为它是专门为推断而设计的返回类型。