Simple flow of control in the effect of scalars

Take this simple bit of code:

var line = "";

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

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

This is definitely not particularly elegant, especially with bad browsing line- however, I think it's pretty easy to read.

Now, trying to translate this directly to the scalaz effect, I came up with:

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

What makes me feel like I'm missing out on something, since that doesn't sound like an improvement at all? Is there any higher order flow control that I am missing?

+5
source share
1 answer

You can do this (at least perhaps) a lot more beautifully by skipping the notation forand using combinators *>and >>=to put everything together:

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

And then:

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

, , , , scalaz.effect, , .

+3

All Articles