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

后端 未结 8 489
-上瘾入骨i
-上瘾入骨i 2021-02-04 00:36

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 =         


        
相关标签:
8条回答
  • 2021-02-04 01:16

    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...

    0 讨论(0)
  • 2021-02-04 01:16
    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
    
    0 讨论(0)
  • 2021-02-04 01:27

    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
    
    0 讨论(0)
  • 2021-02-04 01:28

    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/

    0 讨论(0)
  • 2021-02-04 01:28

    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 讨论(0)
  • 2021-02-04 01:29

    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.

    0 讨论(0)
提交回复
热议问题