Why “do…while” does not exist in F#

2020-05-22 01:23发布

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
                swapped <- true
        i <- i+1

The code is bad without "do...while".
Sadly, "break/continue" are also not available.

标签: f#
8条回答
我只想做你的唯一
2楼-- · 2020-05-22 01:37

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 ()
查看更多
Deceive 欺骗
3楼-- · 2020-05-22 01:39
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
查看更多
祖国的老花朵
4楼-- · 2020-05-22 01:40

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/

查看更多
叛逆
5楼-- · 2020-05-22 01:46

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.

查看更多
我只想做你的唯一
6楼-- · 2020-05-22 01:47

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)
查看更多
唯我独甜
7楼-- · 2020-05-22 01:50

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
查看更多
登录 后发表回答