2013-04-13 12 views
5

Prendete questo semplice pezzo di codice:flusso di controllo semplice a tutti gli effetti scalaz

var line = ""; 

do { 
    println("Please enter a non-empty line: ") 
    line = readLine() 
} while (line.isEmpty()) 

println("You entered a non-empty line: " + line) 

E 'sicuramente non particolarmente elegante, in particolare con la sfortunata scoping di line - tuttavia, penso che sia abbastanza semplice da leggere.

Ora si cerca di tradurre questo direttamente a scalaz effetto, sono venuto su con:

def nonEmptyLine: IO[String] = for { 
    _ <- putStrLn("Please enter a non-empty line:") 
    line <- readLn 
    r <- if (line.isEmpty()) nonEmptyLine else IO(line) 
} yield r 


(for { 
    line <- nonEmptyLine 
    _ <- putStrLn("You entered a non-empty line: " + line) 
} yield()).unsafePerformIO 

Il che mi fa sentire come mi manca qualcosa, in quanto questo non si sente come un miglioramento a tutti? C'è qualcosa di più alto flusso di controllo degli ordini che mi manca?

risposta

3

È possibile effettuare questa (almeno discutibilmente) molto più bella saltando la notazione for e utilizzando i combinatori *> e >>= a tubo tutto insieme:

import scalaz._, Scalaz._, effect._, IO._ 

val prompt = putStrLn("Please enter a non-empty line:") 

def report(line: String) = putStrLn("You entered a non-empty line: " + line) 

def nonEmptyLine: IO[String] = prompt *> readLn >>= (
    (line: String) => if (line.isEmpty) nonEmptyLine else line.point[IO] 
) 

E poi:

scala> (nonEmptyLine >>= report).unsafePerformIO 
Please enter a non-empty line: 
You entered a non-empty line: This is a test. 

In generale, tuttavia, non sono sicuro che dovresti aspettarti che il codice scritto usando scalaz.effect sia più conciso o più facile da leggere di una semplice soluzione imperativa.

Problemi correlati