我找不到“做......而......”
我必须像这样编码:
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 ”,代码就会很糟糕
可悲的是,“休息/继续”也无法使用。
答案 0 :(得分:29)
F#非常适合非函数式编程。事实上,能够以命令式的方式微调算法的某些部分是我语言的主要优点之一。
例如,在处理项目euler问题时,我开始使用不可变集和折叠的干净功能解决方案。完成需要150秒。现在我的算法框架已经允许我分开数据结构并逐个折叠操作,直到我设法将运行时间缩短到5秒。我的最终解决方案非常必要(甚至比同等的C#版本略快)。
正如您所看到的,我首先通过编写功能样式的解决方案来解决它,然后将小部件重写为命令式样式。不必处理索引和其他循环条件明确地保持代码对我来说更容易理解。
一旦你学会了如何像功能性程序员一样思考,你会发现你很少想要休息并继续。这就是我的经历。但是如果你确实需要它们,知道如何以功能方式思考有助于提出解决方法,通常涉及到过去循环的尾递归版本。
当你开始用惯用的F#方式思考时,你可能会看到越来越多的(尾部)递归代码取代你用来做循环结构的东西。哎呀,写F#已经2年了,到目前为止已经扭曲了我的想法,我更有可能选择递归和折叠循环。
每当我认为我需要休息/继续时,我通常不这样做,因为有一个更清洁的算法隐藏并等待离开。最大的挑战是学习如何找到更清洁的版本。我担心许多练习和好的例子是在功能上更好地思考的唯一方法,但我相信这是一项很好的努力。
编辑:具有讽刺意味的是,冒泡排序是一种实际设计用于具有可变内容的数组的算法。任何递归冒泡排序都可能比命令式版本更难理解。我想我刚刚在这里杀了自己的帖子。
答案 1 :(得分:9)
break
和continue
将是一个非常有用的功能添加;它们是保留字,也许我们会在未来的语言版本中看到它们。缺乏这些是偶尔的轻微烦恼,但几乎不会使语言“不合适”。与此同时,一个可变的哨兵也可以,就像你的例子一样。
另见
答案 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