2013-04-13 10 views
5

Weź ten prosty kawałek kodu:Prosty przepływ sterowania w efekcie scalaz

var line = ""; 

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

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

To zdecydowanie nie szczególnie elegancki, szczególnie niefortunne scopingu z line - Myślę jednak, że jest to dość łatwe do odczytania.

Teraz próbują tłumaczyć to bezpośrednio do scalaz efekt, mam wymyślić:

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 

Który sprawia, że ​​czuję się jakbym czegoś brakuje, gdyż nie ma ochoty na poprawę w ogóle? Czy brakuje mi jakiegoś przepływu kontrolnego o wyższym porządku?

Odpowiedz

3

Można zrobić to (przynajmniej prawdopodobnie) wiele ładniejsza omijając notacji for i stosując kombinatorów *> i >>= do wszystkich rur ze sobą:

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] 
) 

, a następnie:

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

Ogólnie rzecz biorąc, nie jestem pewien, czy powinieneś oczekiwać, że kod napisany przy użyciu scalaz.effect będzie bardziej zwięzły lub łatwiejszy do odczytania niż proste rozwiązanie imperatywne.