Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Simple control flow in scalaz effect

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)

It's definitely not particularly elegant, especially with the unfortunate scoping of line -- however, I think it's quite simple to read.

Now trying to translate this directly to scalaz effect, I have come 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

Which makes me feel like I'm missing something, as this doesn't feel like an improvement at all? Is there some higher order control flow stuff I'm missing?

like image 872
Heptic Avatar asked Oct 21 '22 12:10

Heptic


1 Answers

You can make this (at least arguably) a lot prettier by skipping the for notation and using the combinators *> and >>= to pipe 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.

In general, though, I'm not sure you should expect code written using scalaz.effect to be more concise or easier to read than a straightforward imperative solution.

like image 78
Travis Brown Avatar answered Oct 24 '22 10:10

Travis Brown