2012-11-11 9 views
13

Come posso scrivere una funzione che simuli durante il ciclo? Dovrebbero essere necessari 2 argomenti: condizione ed espressione da eseguire.Come scrivere la funzione simulando il loop in Scala

ho provato la seguente:

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

ma sembra che non funziona, per esempio Ho array:

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

anche io ho variabile i:

var i = 0 

voglio stampare tutti gli elementi di arr. Posso farlo con il seguente codice:

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

Vorrei fare lo stesso con la mia funzione whileLoop. Ma non posso scrivere una funzione che faccia riferimento alla variabile e la modifichi. Potrei passare a ciò usando l'array con un solo elemento, ad es.

val nr = Array(0) 

e funzione:

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

e quindi utilizzando nel mio whileLoop:

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

Dopo aver utilizzato i codici di cui sopra ottengo StackOverflowError e NR (0) è uguale a zero . Anche la seguente funzione:

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

fornisce lo stesso risultato.

Come posso scrivere corretto funzionamento whileLoop e l'uso che per stampare tutti i arr elementi?

Grazie in anticipo per i consigli.

risposta

26

Il problema principale con l'implementazione è che la condizione e l'espressione vengono valutate solo una volta, quando si chiama per la prima volta whileLoop. Nella chiamata ricorsiva, si passa semplicemente un valore, non un'espressione.

È possibile risolvere questo problema utilizzando gli argomenti per nome:

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

Per fare un esempio:

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

Nota che le variabili a e i siano correttamente riferimento. Internamente, il compilatore Scala ha creato una funzione per la condizione e l'espressione (blocco) e queste funzioni mantengono un riferimento al loro ambiente.

Si noti inoltre che per suggestione più zucchero sintattico, è possibile definire whileLoop in funzione currified: si

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

Questo permette di chiamare proprio come un ciclo vero e proprio, mentre:

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

Grazie mille - era esattamente ciò di cui avevo bisogno. Ho capito cosa c'era che non andava. – Paul

2

Questo è quello che mi è venuto in mente: prima di tutto, la tua funzione ha bisogno di questi 4 argomenti:

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

penso che il codice è piuttosto auto esplicativo:

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 
} 

questo potrebbe essere fatto molto più gradevole, ma ho cercato di mantenere il più semplice possibile. Per contare tutti gli elementi dell'array, si potrebbe chiamare in questo modo:

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

per stampare ciascuno degli elementi:

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

A proposito, se siete interessati a questo genere di cose, ti consiglierei di acquistare la programmazione funzionale in Scala, ci sono due capitoli che ti permettono di implementare funzioni come questa. È molto divertente.

+0

Grazie anche, è un'alternativa interessante. – Paul

Problemi correlati