【问题标题】:function with mutable arguments具有可变参数的函数
【发布时间】:2020-03-24 20:14:28
【问题描述】:

在 F# 中,函数不允许有可变参数。但如果我有如下功能:


let f x =
    while x>0 do
      printfn "%d" x
      x <- x-1;;

当我编译这个时,我得到一个编译器错误。(不可变) 我将如何修复此功能?

【问题讨论】:

    标签: f#


    【解决方案1】:

    对于传值语义,您可以使用parameter shadowing

    这里,在堆栈上声明了一个阴影(因为它是同名)可变值x

    let f x =
        let mutable x = x
        while x > 0 do
          printfn "%d" x
          x <- x - 1
    

    对于传递引用语义,您必须使用reference cell,这只是传递具有可变字段的对象的一种奇特方式。类似于 C# 中的ref

    let f x =
        while !x > 0 do
          printfn "%d" !x
          x := !x - 1
    

    使用参考单元格:

    let x = (ref 10)
    f x
    Debug.Assert(!x = 0)
    

    【讨论】:

      【解决方案2】:

      你可以这样重写:

      let f x = [x.. -1..1] |> List.iter (printfn "%d")
      

      如果你想保留 while 循环,你可以这样做:

      let f (x : byref<int>)=
          while x>0 do
              printfn "%d" x
              x <- x-1
      
      let mutable x = 5
      f &x
      

      【讨论】:

      • 如果我想保持“While”循环怎么办?
      • 我改变了我的答案来解决这个问题。
      • 请注意byref 有一些怪癖,使其难以通用。
      【解决方案3】:

      取决于您是希望将 x 的最终变异值传递回函数的调用者还是仅在本地对其进行变异。

      对于仅本地突变,只需声明另一个变量,该变量将是可变的,但最初将具有 x 的值:

      let f x =
          let mutable i = x
          while i>0 do
            printfn "%d" i
            i <- i-1
      

      要将结果传递回调用者,您可以使用 ref-cell:

      let f (x: int ref) =
          while x.Value>0 do
            printfn "%d" x.Value
            x := x.Value - 1
      

      请注意,现在您必须通过.Value 属性引用参考单元内容(或者您可以改为使用运算符!,如x := !x - 1),现在通过:= 完成突变.另外,这种函数的使用者现在必须在传递它之前创建一个 ref-cell:

      let x = ref 5
      f x
      printfn "%d" x.Value  // prints "0"
      

      话虽如此,我必须指出,突变通常比纯值更不可靠,更容易出错。在纯函数式编程中编写“循环”的正常方法是通过递归:

      let rec f x = 
          if x > 0 then
              printf "%d" x
              f (x-1)
      

      在这里,对f 的每次调用都会对f 进行另一次调用,x 的值会减少1。这将具有与循环相同的效果,但现在没有突变,这意味着更容易调试和测试。

      【讨论】:

      • 刚刚看到你的答案。隔离是否让我们成为一个思想家?
      • P.S.您的循环缺少 rec
      • 谢谢,已解决
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-12-19
      • 2011-12-24
      • 1970-01-01
      • 2019-06-04
      • 2012-03-06
      • 1970-01-01
      相关资源
      最近更新 更多