2010-02-11 9 views
16

Sul compilando il seguente codice con Scala 2.7.3,Perché l'inferenza di punto e virgola di Scala fallisce qui?

package spoj 

object Prime1 { 
    def main(args: Array[String]) { 
    def isPrime(n: Int) = (n != 1) && (2 to n/2 forall (n % _ != 0)) 
    val read = new java.util.Scanner(System.in) 
    var nTests = read nextInt // [*] 
    while(nTests > 0) { 
     val (start, end) = (read nextInt, read nextInt) 
     start to end filter(isPrime(_)) foreach println 
     println 
     nTests -= 1 
    } 
    } 
} 

ottengo il seguente errore di compilazione:

PRIME1.scala:8: error: illegal start of simple expression 
    while(nTests > 0) { 
    ^
PRIME1.scala:14: error: block must end in result expression, not in definition 
    } 
^
two errors found 

Quando aggiungo un punto e virgola alla fine della riga commentato come [*], il programma si compila bene. Qualcuno può spiegare perché l'inferenza di punto e virgola di Scala non funziona su quella particolare linea?

+1

Appena fuori tema, '2 a n/2' può essere sostituito con' 2 a Math.sqrt (n) '- è la soluzione canonica, anche se non so se fornirà prestazioni migliori (Penso, non lo farà). – incarnate

+0

so che questo è un thread OLD, ma potresti mettere esplicitamente il punto e virgola dopo la riga 'read nextInt'? o questo è un problema perché non c'è argomento fornito a 'nextInt'? – Ramy

+0

@Ramy: leggi le risposte. – missingfaktor

risposta

19

È perché scala sta presupponendo che si sta utilizzando la sintassi a foo b (equivalente a a.foo(b)) nella chiamata a readInt. Cioè, si presuppone che il ciclo while è l'argomento per readInt (ricordiamo che ogni espressione ha un tipo) e, quindi, l'ultima affermazione è una dichiarazione:

var ntests = read nextInt x 

dove x è il tuo blocco po '.

devo dire che, come un punto di preferenza, ora ho tornato ad usare il solito a.foo(b) sintassi sopra a foo ba meno che specificamente si lavora con un modem DSL che è stato progettato con in mente che l'uso (come attori a ! b) . Rende le cose molto più chiare in generale e non si viene morsi da cose strane come questa!

+4

+1 per la raccomandazione all'interno dell'ultimo paragrafo – ziggystar

+0

so che questo è un thread OLD, ma potresti mettere esplicitamente il punto e virgola dopo la riga nextInt? o questo è un problema perché non c'è argomento fornito a nextInt? – Ramy

11

commento aggiuntivo alla risposta da oxbow_lakes ...

var ntests = read nextInt() 

dovrebbe risolvere le cose per voi come alternativa alla virgola

8

Per aggiungere un po 'di più l'inferenza e virgola, Scala in realtà fa questo in due fasi. Prima deduce un token speciale chiamato nl dalla specifica del linguaggio. Il parser consente di utilizzare nl come separatore di istruzioni e come punto e virgola. Tuttavia, nl è consentito anche in altri luoghi dalla grammatica. In particolare, un singolo nl è consentito dopo gli operatori infissi quando il primo token sulla riga successiva può avviare un'espressione - e while può avviare un'espressione, motivo per cui lo interpreta in quel modo. Sfortunatamente, sebbene while possa avviare un'espressione, un'istruzione while non può essere utilizzata in un'espressione infissa, quindi l'errore. Personalmente, sembra che il parser funzioni in modo piuttosto bizzarro, ma dietro tutto questo c'è una ragionevole logica per tutto quello che so!

Per quanto ancora un'altra opzione per gli altri ha suggerito, mettere una nuova riga vuota tra la linea [*] e la linea while sarà anche risolvere il problema, perché è consentito solo un singolo nl dopo operatori infissi, in modo multiplo nl s costringe una diversa interpretazione dal parser.

Problemi correlati