SORU
7 AĞUSTOS 2013, ÇARŞAMBA


Kullanarak görev (Scalaz İteratees değiştirme)ayrıştırma için Akış Scalaz

Giriş

Scalaz 7'In başta büyük-ish dosyaları işleme için bir dizi projeye iteratees, kullanırım. İteratee paketi açıkçası çok parça var eksik ve kullanmak için bir ağrı olan) değiştirmek için tasarlanmış streams, Scalaz geçiş başlamak istiyorum.

Akarsu 25 ** Haskell eden machines (iteratee fikir başka bir varyasyon), dayanmaktadır. Ben de kullandım Haskell makineleri kütüphane biraz, ama ilişkisini makineleri ve akarsu değil tamamen açık (bana en azından), ve belgelerini akarsu kütüphane still a little sparse.

Bu soruyu iteratees yerine akışları kullanarak uygulanan görmek istiyorum bu kadar basit bir ayrıştırma görevi hakkında. Vereceğim cevap bu soruyu kendime eğer kimse beni aşar, ama ben emin değilim sadece kim yapıyor (ya da en azından göz önünde bulundurarak) bu geçiş, ve o zamandan beri çalışmam lazım bu egzersiz her neyse, düşündüm ki belki de bunu halka.

Görev

Sözde bir dosya tokenized edilmiş cümleler ve konuşma parçaları ile etiketlenmiş ettim:

no UH
, ,
it PRP
was VBD
n't RB
monday NNP
. .

the DT
equity NN
market NN
was VBD
illiquid JJ
. .

Bir satır başı token var, konuşma kelimeleri ve parçaları tek bir boşlukla ayrılmış ve boş satır cümle sınırları temsil eder. Bu dosya ayrıştırma ve dizeleri dizilerini listeler kadar iyi temsil edebiliriz, hangi cümle, bir liste dönmek istiyorum:

List((no,UH), (,,,), (it,PRP), (was,VBD), (n't,RB), (monday,NNP), (.,.))
List((the,DT), (equity,NN), (market,NN), (was,VBD), (illiquid,JJ), (.,.)

Her zamanki gibi, geçersiz giriş çarptık ya da okuma istisnalar dosya nazikçe başarısız olmak istiyoruz, manuel kaynakları, vb kapatma hakkında endişe duymak istemiyoruz.

İteratee bir çözüm

Bazı genel dosya için ilk okuma şeyler (gerçekten şu anda bu üst düzey uzaktan bir şey sağlamaz ki iteratee paketinin bir parçası olmalı):

import java.io.{ BufferedReader, File, FileReader }
import scalaz._, Scalaz._, effect.IO
import iteratee.{ Iteratee => I, _ }

type ErrorOr[A] = EitherT[IO, Throwable, A]

def tryIO[A, B](action: IO[B]) = I.iterateeT[A, ErrorOr, B](
  EitherT(action.catchLeft).map(I.sdone(_, I.emptyInput))
)

def enumBuffered(r: => BufferedReader) = new EnumeratorT[String, ErrorOr] {
  lazy val reader = r
  def apply[A] = (s: StepT[String, ErrorOr, A]) => s.mapCont(k =>
    tryIO(IO(Option(reader.readLine))).flatMap {
      case None       => s.pointI
      case Some(line) => k(I.elInput(line)) >>== apply[A]
    }
  )
}

def enumFile(f: File) = new EnumeratorT[String, ErrorOr] {
  def apply[A] = (s: StepT[String, ErrorOr, A]) => tryIO(
    IO(new BufferedReader(new FileReader(f)))
  ).flatMap(reader => I.iterateeT[String, ErrorOr, A](
    EitherT(
      enumBuffered(reader).apply(s).value.run.ensuring(IO(reader.close()))
    )
  ))
}

Ve o cümle bizim okuyucu:

def sentence: IterateeT[String, ErrorOr, List[(String, String)]] = {
  import I._

  def loop(acc: List[(String, String)])(s: Input[String]):
    IterateeT[String, ErrorOr, List[(String, String)]] = s(
    el = _.trim.split(" ") match {
      case Array(form, pos) => cont(loop(acc :  (form, pos)))
      case Array("")        => cont(done(acc, _))
      case pieces           =>
        val throwable: Throwable = new Exception(
          "Invalid line: %s!".format(pieces.mkString(" "))
        )

        val error: ErrorOr[List[(String, String)]] = EitherT.left(
          throwable.point[IO]
        )

        IterateeT.IterateeTMonadTrans[String].liftM(error)
    },
    empty = cont(loop(acc)),
    eof = done(acc, eofInput)
  )
  cont(loop(Nil))
}

Ve son olarak ayrıştırma bizim eylem:

val action =
  I.consume[List[(String, String)], ErrorOr, List] %=
  sentence.sequenceI &=
  enumFile(new File("example.txt"))

Bunun işe yaradığını göstermek edebiliriz:

scala> action.run.run.unsafePerformIO().foreach(_.foreach(println))
List((no,UH), (,,,), (it,PRP), (was,VBD), (n't,RB), (monday,NNP), (.,.))
List((the,DT), (equity,NN), (market,NN), (was,VBD), (illiquid,JJ), (.,.))

Ve işimiz bitti.

İstiyorum

Daha fazla veya daha az aynı programı iteratees yerine Scalaz akışları kullanılarak uygulanan.

CEVAP
7 AĞUSTOS 2013, ÇARŞAMBA


Scalaz-stream bir çözüm:

import scalaz.std.vector._
import scalaz.syntax.traverse._
import scalaz.std.string._

val action = linesR("example.txt").map(_.trim).
  splitOn("").flatMap(_.traverseU { s => s.split(" ") match {
    case Array(form, pos) => emit(form -> pos)
    case _ => fail(new Exception(s"Invalid input $s"))
  }})

Bunun işe yaradığını göstermek edebiliriz:

scala> action.collect.attempt.run.foreach(_.foreach(println))
Vector((no,UH), (,,,), (it,PRP), (was,VBD), (n't,RB), (monday,NNP), (.,.))
Vector((the,DT), (equity,NN), (market,NN), (was,VBD), (illiquid,JJ), (.,.))

Ve işimiz bitti.

traverseU işlevi ortak Scalaz bir kombinatorik. Process monad geçiş için kullanılıyor, bu durumda, 18* *cümle splitOn tarafından oluşturulur. map sequence takip denk geliyor.

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • Benjamin Heckendorn

    Benjamin Hec

    4 Mayıs 2008
  • mist64

    mist64

    30 Mayıs 2006
  • The Pet Collective

    The Pet Coll

    5 Ocak 2012