开发者

Why "do...while" does not exist in F#

I cannot find "do...while..."

I have to code like this:

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
        开发者_JS百科        swapped <- true
        i <- i+1

The code is bad without "do...while".

Sadly, "break/continue" are also not available.


F# is very much suitable for non-functional programming. In fact, being able to fine-tune parts of an algorithm in an imperative style is one of the major strong points of the language for me.

For example, in tackling a project euler problem, I started out with a clean functional solution using immutable sets and folds. It took 150 seconds to complete. Now having the framework of my algorithm in place allowed me to pick apart the data structures and folds operations one at a time until I managed to get the run time down to 5 seconds. My final solution was very much an imperative one (and even slightly faster than an equivalent C# version).

As you can see I solved it by coding a solution in functional style first and then rewrite small parts to an imperative style. Not having to deal with indices and other loop conditions explicitly kept the code more understandable for me.

Once you learn how to think like a functional programmer you'll find that you'll rarely want breaks and continues. That's what I experienced. But if you do need them, knowing how to think in a functional way helps in coming up with work-arounds, usually involving a tail-recursive version of what used to be a loop.

By the time you start thinking more in an idiomatic F# way, you'll probably see more and more (tail-)recursive code replacing what you used to do with looping constructs. Heck, writing F# for 2 years now has warped my mind so far that I'm more likely to pick recursion and folds over loops.

Whenever I think I need break/continue, I usually don't because there's a cleaner version of the algorithm hidden and waiting to get out. The biggest challenge is learning how to find that cleaner version. I'm afraid that lots of practice and good examples are the only way to get better at thinking functionally, but I believe that it's an effort well spent.

Edit: ironically, bubble sort is an algorithm which is actually designed for arrays with mutable contents. Any recursive bubble sort is likely to be harder to understand than an imperative version. I think I just killed my own post here.


It turns out to be quite easy to write a good enough do-while in F# as a higher-order function:

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


break and continue would be a really useful feature additions; they're reserved words, and maybe we'll see them in a future version of the language. The lack of them is an occasional minor annoyance, but hardly makes the language 'unsuitable'. In the mean time, a mutable sentinel works, as you have in your example.

See also

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


do/while is not available because F# is a functional language and this kind of construct is specific to imperative languages.

break/continue is also not available for the same reasons.

However, you can still write do/while in F#. The following code blocks are equivalent :

in C#

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

    System.Console.Write("continue?");
} while (Console.ReadLine() == "y");

in F#

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

while doSomethingAndContinue() do ignore None


Although a bit more verbose, you can use recursive functions to avoid the "do while" as in :

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)


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


I do not know about F# very well, but F# is a functional language. Usually, there is no such thing as "for" or "while" loops in functional programming languages.

Functional languages define functions in a mathematical sense (like f(x) => ...). Writing a program comes down to defining and combining a set of mathematical functions. This means that the only way of coding loops is using recursion.

In Mathematics, there is no way of saying:

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

What you'd do is define f like:

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

And then use this function as in:

y = f(x, 5)

This would be exactly how you implement functions in functional languages. At least, this is true for purely functional languages like Haskell...


You can do something like

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

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

I just recently found this way. It feels a bit hacky but what I like is that you can build something more complex what usually caused issues in 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
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜