Bu kodu göz önünde bulundurun (here'dan alınmış ve satır karakterleri yerine bayt kullanmak için değiştirilmiştir). iyi ölçekli bir dosya (8kb) Bu kod çalıştırmaScalaz7 ile IO nasıl kullanılır? Yığın taşması olmadan yinelemeler var mı?
import java.io.{ File, InputStream, BufferedInputStream, FileInputStream }
import scalaz._, Scalaz._, effect._, iteratee.{ Iteratee => I, _ }
import std.list._
object IterateeIOExample {
type ErrorOr[+A] = EitherT[IO, Throwable, A]
def openStream(f: File) = IO(new BufferedInputStream(new FileInputStream(f)))
def readByte(s: InputStream) = IO(Some(s.read()).filter(_ != -1))
def closeStream(s: InputStream) = IO(s.close())
def tryIO[A, B](action: IO[B]) = I.iterateeT[A, ErrorOr, B] {
EitherT(action.catchLeft).map(r => I.sdone(r, I.emptyInput))
}
def enumBuffered(r: => BufferedInputStream) = new EnumeratorT[Int, ErrorOr] {
lazy val reader = r
def apply[A] = (s: StepT[Int, ErrorOr, A]) => s.mapCont(k =>
tryIO(readByte(reader)) flatMap {
case None => s.pointI
case Some(byte) => k(I.elInput(byte)) >>== apply[A]
})
}
def enumFile(f: File) = new EnumeratorT[Int, ErrorOr] {
def apply[A] = (s: StepT[Int, ErrorOr, A]) =>
tryIO(openStream(f)).flatMap(stream => I.iterateeT[Int, ErrorOr, A](
EitherT(
enumBuffered(stream).apply(s).value.run.ensuring(closeStream(stream)))))
}
def main(args: Array[String]) {
val action = (
I.consume[Int, ErrorOr, List] &=
enumFile(new File(args(0)))).run.run
println(action.unsafePerformIO())
}
}
bir StackOverflowException üretir. Bazı aramalar istisnanın IO yerine Trampoline monad kullanılarak önlenebildiğini gösterdi, ancak bu büyük bir çözüm gibi görünmüyor - programın tamamlanmasını sağlamak için işlevsel saflığı feda ediyor. Bunu düzeltmenin bariz yolu, IO veya Trampoline'ı diğerini sarmak için Monad Transformer olarak kullanmaktır, ancak bunların her birinin transformatör versiyonunun bir uygulamasını bulamıyorum ve işlevsel bir programlama gurusu için yeterli değilim. Kendimi nasıl yazacağımı biliyorum (FP hakkında daha fazla bilgi edinmek, bu projenin amaçlarından biridir, fakat yeni monad transformatörleri yaratmanın şu anki seviyemin biraz üzerinde olduğundan şüpheleniyorum). Sanırım büyük bir IO eylemini, yineleyicilerimin sonucunu oluşturmak, yürütmek ve döndürmek etrafında sarabilirim, ama bu çözümden daha çok bir çözüm gibi görünüyor.
Muhtemelen bazı monad'ler monad trafolarına dönüştürülemez, dolayısıyla IO'yu düşürmeden veya yığının taşmasına gerek kalmadan büyük dosyalarla çalışmanın mümkün olup olmadığını bilmek isterim ve eğer öyleyse, nasıl olur?
Bonus soru: Bir yinelemenin herhangi bir şekilde geri dönüşü dışında işlem yapıldığında hatayla karşılaştığını, bunların oluşturulmasını daha kolay hale getirdiğini belirtmek için bir yol düşünemiyorum. Yukarıdaki kod numaralandırıcıdaki hataları işlemek için EitherT nasıl kullanıldığını gösterir, ancak yineleme için bu nasıl çalışır?
Bu sizin için yararlı olabilir: http://termsandtruthconditions.herokuapp.com/blog/2013/03/16/free-monad/ – Impredicative
Yığın taşmasını önlemek için neden Trampoline kullanmam gerektiğine dair iyi bir açıklama, ama hem IO hem de Trambolinin nasıl kullanılacağını kapsamıyor. – Redattack34
IO zaten tramplen edilmiştir. – Apocalisp