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

时间:2010-06-10 07:44:08

标签: 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

如果没有“ do ... while ”,代码就会很糟糕 可悲的是,“休息/继续”也无法使用。

8 个答案:

答案 0 :(得分:29)

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

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

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

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

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

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

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

答案 1 :(得分:9)

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

另见

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

答案 2 :(得分:7)

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

let doWhile f c =
    f ()
    while c () do
        f ()

答案 3 :(得分: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)

答案 4 :(得分:4)

我不太了解F#,但F#是一种功能语言。通常,在函数式编程语言中没有“for”或“while”循环这样的东西。

功能语言在数学意义上定义函数(如f(x)=&gt; ...)。编写程序归结为定义和组合一组数学函数。这意味着编码循环的唯一方法是使用递归。

在数学方面,没有办法说:

f(x) => "do 5 times this"

您要做的是定义f,如:

                 count > 0  : f(x, count-1)
f(x, count) => {
                 count <= 0 : ...

然后使用此功能,如:

y = f(x, 5)

这正是您在函数式语言中实现函数的方式。 至少,对于像Haskell这样的纯函数语言来说也是如此......

答案 5 :(得分:4)

let bubbleSort (a: _ []) =
  let mutable fin = false
  while not fin do
    fin <- true
    for i=0 to a.Length-2 do
      if a.[i] > a.[i+1] then
        let t = a.[i]
        a.[i] <- a.[i+1]
        a.[i+1] <- t
        fin <- false

答案 6 :(得分:4)

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

由于同样的原因,

break / continue也无法使用。

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

在C#中

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

    System.Console.Write("continue?");
} while (Console.ReadLine() == "y");
在F#中

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

while doSomethingAndContinue() do ignore None

答案 7 :(得分:0)

您可以做类似的事情

let mutable ind = 0
while (
    //Do your stuff here

    //Now condition part return some boolean value
    ind < 10
) do ind <- ind +1

我最近才发现这种方式。感觉有点棘手,但是我喜欢的是您可以构建更复杂的东西,而这通常会导致C#,C ++中的问题。

let mutable ind = 0
while (
    (some condition) && (
    //do something
    let someValue = Eval ....

    //Now more complex condition
    ind + someValue < 10
    )
) do ind <- ind +1