【问题标题】:F# recursion inside type definition类型定义内的 F# 递归
【发布时间】:2010-09-05 21:37:46
【问题描述】:

我在尝试在 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

如果我尝试使用“添加测试”,我会收到堆栈溢出错误,我认为这是由于我的类型本身依赖于“+”的 (+) 定义。

有什么办法可以解决这个问题吗?任何帮助将不胜感激。

非常感谢,阿什

【问题讨论】:

    标签: f# recursion


    【解决方案1】:

    如您所想,问题在于 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} 
    

    这将仅在实际使用时评估df的值,因此+操作将计算d的值,并且只为df提供一个惰性值(如果有人需要可以评估)它)。

    另一种选择是使Diff 类型成为可区分的联合并将零表示为特殊值(而不是递归记录),除非您对其他内容使用递归引用,否则这将起作用。声明大致类似于:

    type Diff = 
        | DiffValue of double * Diff
        | DiffZero 
        static member (+) // etc...
    

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

    【讨论】:

      猜你喜欢
      • 2018-03-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-10
      • 1970-01-01
      • 1970-01-01
      • 2021-07-11
      相关资源
      最近更新 更多