Last active
October 21, 2017 14:06
-
-
Save phenan/e17398a0c8dab9207bbb8800cebfec2d to your computer and use it in GitHub Desktop.
バイナリ用プリンタコンビネータ(?)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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