代码之家  ›  专栏  ›  技术社区  ›  kev

为什么F中不存在“do…while”#

f#
  •  21
  • kev  · 技术社区  · 14 年前

    我找不到“做…而

    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
    

    代码不好,没有“ 做……一会儿
    中断/继续

    7 回复  |  直到 14 年前
        1
  •  33
  •   cfern    14 年前

    例如,在处理一个projecteuler问题时,我首先使用了一个干净的函数解决方案,使用了不可变的集合和折叠。花了150秒才完成。现在有了我的算法框架,我就可以把数据结构分开,一次折叠一个操作,直到我成功地把运行时间缩短到5秒。我的最终解决方案是非常必要的(甚至比同等的C版本还要快一些)。

    如您所见,我首先用函数式风格编写解决方案,然后将小部分重写为命令式风格,从而解决了这个问题。不必显式地处理索引和其他循环条件,使代码更易于理解。

    一旦你学会了如何像一个函数式程序员那样思考,你就会发现你很少需要休息和继续。这就是我的经历。但是,如果您确实需要它们,了解如何以函数方式进行思考有助于找到解决方法,通常涉及到以前是循环的尾部递归版本。

    当你开始以惯用的F#方式思考更多的问题时,你可能会看到越来越多的(尾部)递归代码取代了你过去使用循环结构所做的事情。见鬼,写了2年的F#现在已经扭曲了我的思维,以至于我更倾向于选择递归和循环上的折叠。

    每当我认为我需要中断/继续时,我通常不会这样做,因为隐藏了一个更干净的算法版本,等待退出。最大的挑战是学习如何找到更干净的版本。我担心大量的实践和好的例子是提高功能性思维的唯一途径,但我相信这是一种很好的努力。

        2
  •  13
  •   rwallace    9 年前

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

    let doWhile f c =
        f ()
        while c () do
            f ()
    
        3
  •  9
  •   rmunn    8 年前

    break continue 将是一个真正有用的功能补充;它们是保留词,也许我们会在未来的语言版本中看到它们。缺少它们只是偶尔的小麻烦,但很难让语言变得“不合适”。同时,一个可变的哨兵可以工作,就像你在例子中看到的那样。

    另请参见

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

        4
  •  6
  •   andri    12 年前

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

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

    在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
    
        5
  •  5
  •   xxx    14 年前

    尽管有点冗长,但您可以使用递归函数来避免“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)
    
        6
  •  4
  •   Thorsten Dittmar    14 年前

    我对F不太了解,但F是一种函数语言。通常,函数式编程语言中没有“for”或“while”循环。

    函数语言在数学意义上定义函数(如f(x)=>…)。编写一个程序可以归结为定义和组合一组数学函数。这意味着编码循环的唯一方法是使用递归。

    在数学中,没有办法说:

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

    你要做的就是定义 f 比如:

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

    y = f(x, 5)
    

    这正是用函数式语言实现函数的方式。 至少,像Haskell这样的纯函数式语言是这样的。。。

        7
  •  4
  •   Adam Pridmore J D    7 年前
    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
    
        8
  •  0
  •   user1325696    5 年前

    你可以这样做

    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