类型定义内的F#递归

类型定义内的F#递归,f#,recursion,F#,Recursion,我在尝试在F#中实现自动微分时遇到了一些问题。我认为问题在于评估是否“懒惰” 这是我的密码: type Diff = {d : double; df : Diff} static member (+) (x : Diff, y : Diff) = {d = x.d + y.d; df = x.df + y.df} static member (-) (x : Diff, y : Diff) = {d = x.d - y.d; df = x.

我在尝试在F#中实现自动微分时遇到了一些问题。我认为问题在于评估是否“懒惰”

这是我的密码:

type Diff =
    {d : double; df : Diff}
    static member (+) (x : Diff, y : Diff) =
        {d = x.d + y.d; df = x.df + y.df}
    static member (-) (x : Diff, y : Diff) =
        {d = x.d - y.d; df = x.df - y.df}
    static member (*) (x : Diff, a : double) =
        {d = x.d * a; df = x.df * a}
    static member (*) (x : Diff, y : Diff) =
        {d = x.d * y.d; df = (x.df * y) + (y.df * x)}

let rec dZero = {d = 0.0; df = dZero}

let dConst x = {d = x; df = dZero}

let dId x = {d = x; df = dConst 1.0}

let test = dId 5.0

let add (x:Diff) = (x+x).d
如果我尝试使用“addtest”,我会得到一个堆栈溢出错误,我认为这是由于依赖于“+”的类型本身中(+)的定义造成的

我有办法解决这个问题吗?任何帮助都将不胜感激


非常感谢,Ash

正如您所想,问题在于F#不使用延迟求值,并且您正在创建的数据结构是“无限的”(因为dZero递归地引用自身)。当计算
+
时,操作员对
df
值调用
+
,然后对
df.df
值调用
+
,依此类推

纠正此问题的一种方法是使记录的
df
成员显式延迟:

type Diff = 
    {d : double; df : Lazy<Diff>} 
    static member (+) (x : Diff, y : Diff) = 
        {d = x.d + y.d; df = lazy (x.df.Value + y.df.Value) } 
    static member (-) (x : Diff, y : Diff) = 
        {d = x.d - y.d; df = lazy (x.df.Value - y.df.Value) } 
    static member (*) (x : Diff, a : double) = 
        {d = x.d * a; df = lazy (x.df.Value * a) } 
    static member (*) (x : Diff, y : Diff) = 
        {d = x.d * y.d; df = lazy ((x.df.Value * y) + (y.df.Value * x)) } 

let rec dZero = {d = 0.0; df = lazy dZero} 
let dConst x = {d = x; df = lazy dZero} 
let dId x = {d = x; df = lazy dConst 1.0} 

这将使实现更长一些,因为您需要在所有基本操作中检查
Zero
情况。在这种情况下,您只会创建有限的数据结构(并且操作符会急切地处理它们)。

正如您所想,问题在于F#不使用延迟求值,并且您正在创建的数据结构是“无限的”(因为
dZero
递归地引用自身)。当计算
+
时,操作员对
df
值调用
+
,然后对
df.df
值调用
+
,依此类推

纠正此问题的一种方法是使记录的
df
成员显式延迟:

type Diff = 
    {d : double; df : Lazy<Diff>} 
    static member (+) (x : Diff, y : Diff) = 
        {d = x.d + y.d; df = lazy (x.df.Value + y.df.Value) } 
    static member (-) (x : Diff, y : Diff) = 
        {d = x.d - y.d; df = lazy (x.df.Value - y.df.Value) } 
    static member (*) (x : Diff, a : double) = 
        {d = x.d * a; df = lazy (x.df.Value * a) } 
    static member (*) (x : Diff, y : Diff) = 
        {d = x.d * y.d; df = lazy ((x.df.Value * y) + (y.df.Value * x)) } 

let rec dZero = {d = 0.0; df = lazy dZero} 
let dConst x = {d = x; df = lazy dZero} 
let dId x = {d = x; df = lazy dConst 1.0} 
这将使实现更长一些,因为您需要在所有基本操作中检查
Zero
情况。在这种情况下,您将只创建有限的数据结构(并且操作符将热切地处理它们)