Следующий код для чтения и сопоставления строк файла работает нормально:scalaz, читать и отображать строки файла
def readLines(fileName: String) = scala.io.Source.fromFile(fileName).getLines
def toInt(line: String) = line.toInt
val numbers: Iterator[Int] = readLines("/tmp/file.txt").map(toInt).map(_ * 2)
println(numbers.toList)
Я получаю итератор Int
с, если исполнение идет хорошо. Но программа выдает исключение, если файл не найден, или какая-либо строка содержит буквы.
Как я могу преобразовать программу для использования монадов-скаразов и получить Disjunction[Exception, List[Int]]
?
Я попробовал это на scalaz 7.2.6, но он не компилируется:
import scalaz.Scalaz._
import scalaz._
def readLines(fileName: String): Disjunction[Any, List[String]] =
try { scala.io.Source.fromFile(fileName).getLines.toList.right }
catch { case e: java.io.IOException => e.left}
def toInt(line: String): Disjunction[Any, Int] =
try { line.toInt.right }
catch { case e: NumberFormatException => e.left}
val numbers: Disjunction[Any, Int] = for {
lines: List[String] <- readLines("/tmp/file.txt")
line: String <- lines
n: Int <- toInt(line)
} yield (n * 2)
он не компилировать с этими ошибками:
Error:(89, 37) could not find implicit value for parameter M: scalaz.Monoid[Any]
lines: List[String] <- readLines("/tmp/file.txt")
Error:(89, 37) not enough arguments for method filter: (implicit M: scalaz.Monoid[Any])scalaz.\/[Any,List[String]].
Unspecified value parameter M.
lines: List[String] <- readLines("/tmp/file.txt")
Error:(91, 20) could not find implicit value for parameter M: scalaz.Monoid[Any]
n: Int <- toInt(line)
Error:(91, 20) not enough arguments for method filter: (implicit M: scalaz.Monoid[Any])scalaz.\/[Any,Int].
Unspecified value parameter M.
n: Int <- toInt(line)
Я не понимаю ошибок. в чем проблема?
и как улучшить этот код, чтобы он не считывал весь файл в память, но он считывает и отображает каждую строку за раз?
Обновление: Ответ от Filippo
import scalaz._
def readLines(fileName: String) = \/.fromTryCatchThrowable[List[String], Exception] {
scala.io.Source.fromFile(fileName).getLines.toList
}
def toInt(line: String) = \/.fromTryCatchThrowable[Int, NumberFormatException](line.toInt)
type λ[+A] = Exception \/ A
val numbers = for {
line: String <- ListT[λ, String](readLines("/tmp/file.txt"))
n: Int <- ListT[λ, Int](toInt(line).map(List(_)))
} yield n * 2
println(numbers)
прохладно для 'Disjunction.fromTryCatchThrowable'. Хорошо, я вижу проблему (от строк к строке), но что такое решение? Я обновил вопрос, чтобы сделать задачу более ясной. –
@DavidPortabella Я ответил, редактируя свой ответ. –
ничего себе, это работает! (программа не компилировалась, но она была быстро исправлена. Я добавил ваш ответ (исправленный) в конец моего вопроса. Я удалю его из моего вопроса, если вы сможете исправить его в своем ответе). –