2012-11-11 32 views
13

Làm cách nào để viết chức năng mô phỏng trong khi lặp? Cần có 2 đối số: điều kiện và biểu thức để thực hiện.Cách viết chức năng mô phỏng trong khi vòng lặp trong Scala

tôi thử như sau:

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

Nhưng có vẻ như nó không hoạt động, ví dụ tôi có mảng:

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

Ngoài ra tôi có biến i:

var i = 0 

Tôi muốn in tất cả các yếu tố của arr. Tôi có thể làm điều đó với đoạn mã sau:

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

Tôi muốn làm điều tương tự sử dụng chức năng whileLoop tôi. Nhưng tôi không thể viết chức năng mà tham chiếu đến biến và sửa đổi đó. Tôi có thể sử dụng mảng đó chỉ với một phần tử, ví dụ:

val nr = Array(0) 

và chức năng:

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

và sau đó sử dụng trong tôi whileLoop:

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

Sau khi sử dụng mã trên tôi nhận được StackOverflowError và nr (0) là bằng zero . Ngoài chức năng sau:

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

cho cùng một kết quả.

Làm thế nào tôi có thể viết đúng chức năng whileLoop và sử dụng để in tất cả arr yếu tố?

Cảm ơn trước lời khuyên.

Trả lời

26

Vấn đề chính với việc triển khai của bạn là điều kiện và biểu thức chỉ được đánh giá một lần, khi bạn lần đầu tiên gọi whileLoop. Trong cuộc gọi đệ quy, bạn chỉ cần chuyển một giá trị, chứ không phải một biểu thức.

Bạn có thể giải quyết điều này bằng cách sử dụng bằng tên đối số:

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

Như một ví dụ:

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

Lưu ý rằng các biến ai được tham chiếu một cách chính xác. Bên trong, trình biên dịch Scala đã xây dựng hàm cho cả điều kiện và biểu thức (khối) và các hàm này duy trì tham chiếu đến môi trường của chúng.

Cũng lưu ý rằng cho khiếp sợ đường cú pháp hơn, bạn có thể định nghĩa whileLoop như một hàm currified:

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

này cho phép bạn gọi nó là giống như một vòng lặp while thực tế:

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

Cảm ơn bạn rất nhiều - đó là chính xác những gì tôi cần. Tôi không hiểu chuyện gì đã xảy ra. – Paul

2

này là những gì tôi đã đưa ra: trước hết, chức năng của bạn cần 4 đối số sau:

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

tôi nghĩ rằng mã là khá tự giải thích:

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 
} 

này có thể được thực hiện đẹp hơn rất nhiều, nhưng tôi đã cố gắng để giữ cho nó càng đơn giản càng tốt. Để đếm tất cả các yếu tố trong mảng, bạn sẽ gọi nó là như vậy:

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

để in của mỗi nguyên tố:

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

Bằng cách này, nếu bạn quan tâm đến loại công cụ này, tôi sẽ khuyên bạn nên u mua chức năng lập trình trong Scala, có hai chương mà làm cho bạn thực hiện các chức năng như thế này. Đó là rất nhiều niềm vui.

+0

Cảm ơn cũng, đó là lựa chọn thú vị. – Paul

Các vấn đề liên quan