F#中不存在"do ... while"的原因

kev*_*kev 22 f#

我找不到"做......而......"

我必须像这样编码:

let bubbleSort a=
    let n = Array.length a
    let mutable swapped = true
    let mutable i = 0
    while swapped do
        swapped <- false
        for j = 0 to n-i-2 do
            if a.[j] > a.[j+1] then
                let t = a.[j]
                a.[j] <- a.[j+1]
                a.[j+1] <- t
                swapped <- true
        i <- i+1
Run Code Online (Sandbox Code Playgroud)

没有" do ... while " 的代码很糟糕.
可悲的是," 休息/继续 "也无法使用.

cfe*_*ern 30

F#非常适合非函数式编程.事实上,能够以命令式的方式微调算法的某些部分是我语言的主要优点之一.

例如,在解决项目euler问题时,我开始使用一个使用不可变集和折叠的干净功能解决方案.完成需要150秒.现在我的算法框架已经允许我分开数据结构并逐个折叠操作,直到我设法将运行时间缩短到5秒.我的最终解决方案非常迫切(甚至比同等的C#版本略快).

正如您所看到的,我首先通过编写功能样式的解决方案来解决它,然后将小部件重写为命令式样式.不必处理索引和其他循环条件明确地保持代码对我来说更容易理解.

一旦你学会了如何像功能性程序员一样思考,你会发现你很少想要休息并继续.这就是我的经历.但是如果你确实需要它们,知道如何以功能方式思考有助于提出解决方法,通常涉及到过去循环的尾递归版本.

当你开始以惯用的F#方式思考时,你可能会看到越来越多的(尾部)递归代码取代你以前用循环结构做的事情.哎呀,写F#已经2年了,到目前为止已经扭曲了我的想法,我更有可能选择递归和折叠循环.

每当我认为我需要休息/继续时,我通常不会因为有一个更清晰的算法隐藏并等待离开.最大的挑战是学习如何找到更清洁的版本.我担心很多练习和很好的例子是在功能上更好地思考的唯一方法,但我相信这是一项很好的努力.

编辑:具有讽刺意味的是,冒泡排序是一种实际设计用于具有可变内容的数组的算法.任何递归冒泡排序都可能比命令式版本更难理解.我想我刚刚在这里杀了自己的帖子.

  • @Juliet:我想尊重项目Euler的不发布解决方案的要求(至少对于编号较高的问题).但我可以告诉你我是如何获得这样的加速:我用循环代替迭代序列表达式.我将BigRational替换为我自己的分数类,它适合整数.最重要的加速:我用可变的HashSet <_>替换了Set <_>.所以加速并不是真的由于功能改变 - >命令式风格,而是由于为我的问题选择了更合适的数据结构(O(1)lookup vs. O(n log n)). (2认同)

Bri*_*ian 9

break并且continue将是一个非常有用的功能添加; 它们是保留字,也许我们会在未来的语言版本中看到它们.缺乏这些是偶尔的轻微烦恼,但几乎不会使语言"不合适".与此同时,一个可变的哨兵也可以,就像你的例子中一样.

也可以看看

http://tomasp.net/blog/imperative-ii-break.aspx/

  • 恕我直言,F#中不存在break&continue的原因是因为核心语言本质上是OCaml.由于极低的开销,OCaml编译器产生非常有效的异常处理,非常适合流控制.另一方面,.NET平台的异常处理效率低得多,完全不适合控制流程. (3认同)

rwa*_*ace 8

事实证明,在F#中写一个足够好的do-while作为高阶函数是非常容易的:

let doWhile f c =
    f ()
    while c () do
        f ()
Run Code Online (Sandbox Code Playgroud)


and*_*dri 7

do/while 不可用,因为 F# 是一种函数式语言,并且这种构造特定于命令式语言。

出于同样的原因,中断/继续也不可用。

但是,您仍然可以在 F# 中编写 do/while。以下代码块是等效的:

在 C# 中

do
{
    System.Console.WriteLine("processing something...");
    System.Console.WriteLine("doing something complicated");

    System.Console.Write("continue?");
} while (Console.ReadLine() == "y");
Run Code Online (Sandbox Code Playgroud)

在 F#

let doSomethingAndContinue() =
  printfn "processing something..."
  printfn "doing something complicated"
  printf  "continue?"
  System.Console.ReadLine()="y"

while doSomethingAndContinue() do ignore None
Run Code Online (Sandbox Code Playgroud)


小智 5

虽然有点冗长,但您可以使用递归函数来避免"do while",如:

let swap (a:int[]) i j =
    let t = a.[i]
    a.[i] <- a.[j]
    a.[j] <- t

let rec bubbleSortAux a nMax j swapped =
  if j >= 0 && j <= nMax then
    if a.[j] > a.[j+1] then
      swap a j (j+1)
      bubbleSortAux a nMax (j+1) true
    else
      bubbleSortAux a nMax (j+1) false
  else
    swapped

let rec bubbleSortLoop a nMax =
  if bubbleSortAux a nMax 0 false then
    bubbleSortLoop a (nMax - 1)

let bubbleSort a =
    bubbleSortLoop a (a.Length - 2)
Run Code Online (Sandbox Code Playgroud)