2012-11-11 35 views
13

如何編寫模擬while循環的函數?它應該有兩個參數:條件和表達式來執行。如何在Scala中編寫函數模擬循環while

我試過如下:

val whileLoop: (Boolean,Any)=>Unit = (condition:Boolean, expression:Any) => { 
expression 
if(condition) whileLoop(condition,expression) 
() }  

但現在看來,這是不行的,例如我有數組:

val arr = Array[Int](-2,5,-5,9,-3,10,3,4,1,2,0,-20)  

另外我有可變

var i = 0 

我想打印ARR的所有元素。我可以做到這一點下面的代碼:

while(i<arr.length) { println(tab(i)); i+=1 } 

我想用我的while循環功能做同樣的。但是我不能編寫引用變量並修改它的函數。我只能使用一個元素來傳遞數組,例如

val nr = Array(0) 

和功能:

val printArray: Array[Int]=>Unit = (n:Array[Int]) => { 
println(arr(n(0))) 
n(0)+=1 
() 
} 

,然後用我的while循環

whileLoop(nr(0)<arr.length, printArray) 

使用上面的代碼後,我得到的StackOverflowError和NR(0)是等於零。還有以下功能:

val printArray: Array[Int]=>Unit = (n:Array[Int]) => { 
println(arr(nr(0))) 
nr(0)+=1 
() 
} 

給出了相同的結果。

我怎麼能寫正確的功能while循環,並用它來打印所有改編元素?

在此先感謝您的建議。

回答

26

您的實施的主要問題是條件和表達式只評估一次,當您第一次調用whileLoop時。在遞歸調用中,您只需傳遞一個值,而不是表達式。

您可以通過使用名稱參數解決這個問題:

def whileLoop(cond : =>Boolean, block : =>Unit) : Unit = 
    if(cond) { 
    block 
    whileLoop(cond, block) 
    } 

舉個例子:

scala> val a = Array(1, 2, 3) 
scala> var i = 0 
scala> whileLoop(i < a.length, { println(i); i += 1 }) 
1 
2 
3 

注意,變量ai被正確引用。在內部,Scala編譯器針對條件和表達式(塊)構建了函數,並且這些函數保持對其環境的引用。

還要注意的是更多的語法糖迷死人,你可以定義whileLoop作爲currified功能:

def whileLoop(cond : =>Boolean)(block : =>Unit) : Unit = 
    if(cond) { 
    block 
    whileLoop(cond)(block) 
    } 

這使您可以調用它就像一個實際的while循環:

whileLoop(i < a.length) { 
    println(a(i)) 
    i += 1 
} 
+1

非常感謝 - 這正是我所需要的。我明白什麼是錯的。 – Paul

2

這是我想到的: 首先,你的功能需要這4個參數:

- array which is yet to be processed 
- predicate that tells the function when to stop 
- function that takes the array to be processed and current state and produces a new state 
- and state that is being propagated through the recurion: 

我認爲的代碼是非常自我解釋:

def whileFunc[A,B](over: Array[A], predicate: Array[A] => Boolean, apply: (Array[A],B) => B, state: B):B = { 
    val doIterate = predicate(over) 
    if(doIterate) whileFunc(over.tail, predicate, apply, apply(over,state)) else state 
} 

這可能是做了很多更好,但我試圖保持儘可能簡單。要計算在陣列中的所有元素,只需要調用它像這樣:

scala>  whileFunc(Array(1,2,3), (a:Array[Int]) => !a.isEmpty,(a:Array[Int],s: Int) => s + a.head, 0) 
res5: Int = 6 

打印元件的每個:

whileFunc[Int, Unit](Array(1,2,3), (a:Array[Int]) => !a.isEmpty,(a:Array[Int],s: Unit) => print(a.head), Unit) 
123 

順便說一句,如果你有興趣在這種東西,我會建議你在Scala中購買函數式編程,有兩章使你可以實現像這樣的功能。其樂無窮。

+0

也謝謝,這是一個有趣的選擇。 – Paul