Skip to content

Instantly share code, notes, and snippets.

@phenan
Last active October 21, 2017 14:06
Show Gist options
  • Save phenan/e17398a0c8dab9207bbb8800cebfec2d to your computer and use it in GitHub Desktop.
Save phenan/e17398a0c8dab9207bbb8800cebfec2d to your computer and use it in GitHub Desktop.
バイナリ用プリンタコンビネータ(?)
import java.io._
import scalaz._
import scalaz.std.list._
import scalaz.syntax.traverse._
// Tries.scala (https://gist.github.com/phenan/63833c2cc715c96c02a4c33e17d9e2ac)
import tries._
/**
* Created by phenan on 2017/10/20.
*/
package object combinator {
class ByteWriter private (out: DataOutputStream) {
def u1 (n: Int): Tries[Unit] = Tries(out.writeByte(n))
def u2 (n: Int): Tries[Unit] = Tries(out.writeShort(n))
def s1 (n: Byte): Tries[Unit] = Tries(out.writeByte(n.toInt))
def s2 (n: Short): Tries[Unit] = Tries(out.writeShort(n.toInt))
def s4 (n: Int): Tries[Unit] = Tries(out.writeInt(n))
def s8 (n: Long): Tries[Unit] = Tries(out.writeLong(n))
def f4 (n: Float): Tries[Unit] = Tries(out.writeFloat(n))
def f8 (n: Double): Tries[Unit] = Tries(out.writeDouble(n))
def utf (n: String): Tries[Unit] = Tries(out.writeUTF(n))
def bytes (n: Array[Byte]): Tries[Unit] = Tries(out.write(n))
private def close(): Tries[Unit] = Tries(out.close())
}
object ByteWriter {
def write (f: ByteWriter => Tries[Unit]): Tries[Array[Byte]] = {
val stream = new ByteArrayOutputStream()
for {
writer <- Tries { new ByteWriter(new DataOutputStream(new BufferedOutputStream(stream))) }
_ <- f(writer)
_ <- writer.close()
} yield stream.toByteArray
}
}
type BytePrinter[-T] = T => ReaderT[Tries, ByteWriter, Unit]
trait BytePrinters {
val u1: BytePrinter[Int] = a => Kleisli(_.u1(a))
val u2: BytePrinter[Int] = a => Kleisli(_.u2(a))
val s1: BytePrinter[Byte] = a => Kleisli(_.s1(a))
val s2: BytePrinter[Short] = a => Kleisli(_.s2(a))
val s4: BytePrinter[Int] = a => Kleisli(_.s4(a))
val s8: BytePrinter[Long] = a => Kleisli(_.s8(a))
val f4: BytePrinter[Float] = a => Kleisli(_.f4(a))
val f8: BytePrinter[Double] = a => Kleisli(_.f8(a))
val utf: BytePrinter[String] = a => Kleisli(_.utf(a))
val bytes: BytePrinter[Array[Byte]] = a => Kleisli(_.bytes(a))
def rep [T] (printer: BytePrinter[T]): BytePrinter[List[T]] = list => Kleisli(w => list.traverse_(printer(_).run(w)))
def failure[T] (f: T => Exception): BytePrinter[T] = t => Kleisli(_ => Fails(f(t)): Tries[Unit])
def list [T] (p: BytePrinter[T]): BytePrinter[List[T]] = list => u2 (list.length) >> rep (p)(list)
}
implicit class BytePrinterUtil [T] (printer: => BytePrinter[T]) {
def print (t: T): Tries[Array[Byte]] = ByteWriter.write(w => printer(t).run(w))
}
implicit class ReaderT_Tries_BW_Unit_Util (a: => ReaderT[Tries, ByteWriter, Unit]) {
// workaround: compiler sometimes cannot infer that Kleisli[\/[Throwable, ?], ByteWriter, Unit] is a monad
def >> (b: => ReaderT[Tries, ByteWriter, Unit]): ReaderT[Tries, ByteWriter, Unit] = a.flatMap(_ => b)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment