Skip to content
This repository
Fetching contributors…

Octocat-spinner-32-eaf2f5

Cannot retrieve contributors at this time

file 141 lines (104 sloc) 4.981 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
package scalaz

import java.io._

package object effects {

  import Scalaz._
  import Free._
  
  private[effects] val realWorld = World[RealWorld]()

  /** Put a value in a state thread */
  def returnST[S, A](a: => A): ST[S, A] = ST(s => Return((s, a)))

  /** Run a state thread */
  def runST[A](f: Forall[({type λ[S] = ST[S, A]})#λ]): A =
    f.apply.apply(realWorld).run._2

  /** Allocates a fresh mutable reference. */
  def newVar[S, A](a: A): ST[S, STRef[S, A]] =
    returnST(new STRef[S, A](a))

  /** Allocates a fresh mutable array. */
  def newArr[S, A:Manifest](size: Int, z: A): ST[S, STArray[S, A]] =
    returnST(new STArray[S, A](size, z))

  /** Allows the result of a state transformer computation to be used lazily inside the computation. */
  def fixST[S, A](k: (=> A) => ST[S, A]): ST[S, A] = ST(s => {
    lazy val ans: Trampoline[(World[S], A)] =
      Suspend(() => r flatMap (x => k(x)(s)))
    lazy val r: Trampoline[A] =
      ans.map(_._2)
    Suspend(() => ans)
  })

  /** Accumulates an integer-associated list into an immutable array. */
  def accumArray[F[_]:Foldable, A: Manifest, B](size: Int, f: (A, B) => A, z: A, ivs: F[(Int, B)]): ImmutableArray[A] = {
    type STA[S] = ST[S, ImmutableArray[A]]
    runST(new Forall[STA] {
      def apply[S] = for {
        a <- newArr(size, z)
        _ <- ivs.foldMap(x => a.update(f, x._1, x._2))
        frozen <- a.freeze
      } yield frozen
    })
  }

  implicit def stMonoid[S, A: Monoid]: Monoid[ST[S, A]] = Monoid.liftMonoid[({ type λ[A] = ST[S, A] })#λ, A]
  implicit def ioMonoid[A: Monoid]: Monoid[IO[A]] = Monoid.liftMonoid

  implicit def stApplicative[S]: Applicative[({ type λ[A] = ST[S, A] })#λ] = stMonad[S]

  implicit def stMonad[S]: Monad[({ type λ[A] = ST[S, A] })#λ] = new Monad[({ type λ[A] = ST[S, A] })#λ] {
    def pure[A](a: => A) = returnST(a)
    def bind[A, B](m: ST[S, A], f: A => ST[S, B]): ST[S, B] = m flatMap f
  }

  /** Equality for STRefs is reference equality */
  implicit def stRefEqual[S, A]: Equal[STRef[S, A]] = new Equal[STRef[S, A]] {
    def equal(s1: STRef[S, A], s2: STRef[S, A]): Boolean = s1 == s2
  }

  // Implicit conversions between IO and ST
  implicit def stToIO[A](st: ST[RealWorld, A]): IO[A] = IO(s => st(s))
  implicit def ioToST[A](io: IO[A]): ST[RealWorld, A] = ST(s => io(s))
 
  /** Perform the given side-effect in an IO action */
  def io[A](a: => A) = IO.ioPure pure a

  /** Get the next character from standard input */
  def getChar: IO[Char] = io { readChar }

  /** Write a character to standard output */
  def putChar(c: Char): IO[Unit] = io { print(c); () }

  /** Write a String to standard output */
  def putStr(s: String): IO[Unit] = io { print(s); () }

  /** Write a String to standard output, followed by a newline */
  def putStrLn(s: String): IO[Unit] = io { println(s); () }

  /** Read the next line from standard input */
  def readLn: IO[String] = io { readLine }

  /** Print the given object to standard output */
  def putOut[A](a: A): IO[Unit] = io { print(a); () }

  import IterV._
  import java.io._

  /** Repeatedly apply the given action, enumerating the results. */
  def enumerateBy[A](action: IO[A]): EnumeratorM[IO, A] = new EnumeratorM[IO, A] {
    def apply[B](i: IterV[A, B]): IO[IterV[A, B]] = i match {
      case Done(a, s) => io { Done(a, s) }
      case Cont(k) => action map (a => k(El(a)))
    }
  }

  /** Enumerate the lines on standard input as Strings */
  val getLines: EnumeratorM[IO, String] = getReaderLines(new BufferedReader(new InputStreamReader(System.in)))

  /** Read a line from a buffered reader */
  def rReadLn(r: BufferedReader): IO[Option[String]] = io { Option(r.readLine) }

  /** Write a string to a PrintWriter */
  def wPutStr(w: PrintWriter, s: String): IO[Unit] = io { w.print(s) }

  /** Write a String to a PrintWriter, followed by a newline */
  def wPutStrLn(w: PrintWriter, s: String): IO[Unit] = io { w.println(s) }

  /** Enumerate the lines from a BufferedReader */
  def getReaderLines(r: => BufferedReader): EnumeratorM[IO, String] = new EnumeratorM[IO, String] {
    def apply[A](it: IterV[String, A]) = {
      def loop(i: IterV[String, A]): IO[IterV[String, A]] = i.fold(
        done = (_,_) => io { i },
        cont = k => for {
          s <- rReadLn(r)
          a <- s.map(l => loop(k(El(l)))).getOrElse(io(i))
        } yield a
      )
      loop(it)
    }
  }

  def closeReader(r: Reader): IO[Unit] = io { r.close }

  def getFileLines(f: File): EnumeratorM[IO, String] = new EnumeratorM[IO, String] {
    def apply[A](i: IterV[String, A]) = bufferFile(f).bracket(closeReader)(getReaderLines(_)(i))
  }

  def bufferFile(f: File): IO[BufferedReader] = io { new BufferedReader(new FileReader(f)) }

  // Mutable variables in the IO monad
  def newIORef[A](a: => A) = stToIO(newVar(a)) >>= (v => io { new IORef(v) })

  /** Throw the given error in the IO monad. */
  def throwIO[A](e: Throwable): IO[A] = IO(rw => throw e)

}

Something went wrong with that request. Please try again.