Skip to content

Instantly share code, notes, and snippets.

@akihiro4chawon
Created January 4, 2012 02:37
Show Gist options
  • Select an option

  • Save akihiro4chawon/1558173 to your computer and use it in GitHub Desktop.

Select an option

Save akihiro4chawon/1558173 to your computer and use it in GitHub Desktop.
arm arrow
import scalaz._
import Scalaz._
import scala.util.control.Exception._
package com.github.akihiro4chawon.arm.arrow {
// Resource から 最終製品までの供給網
trait SupplyChain[-T, +R] {
def backorder[S](f: R => S, v: T): S
def produce[S](v: T): R = backorder(identity, v)
def either(v: T): Either[Throwable, R] = allCatch either produce(v)
def opt(v: T): Option[R] = allCatch opt produce(v)
}
// 開け閉めが必要な Resource の供給
class ResourceSupply[-T, +R: Resource](open: T => R) extends SupplyChain[T, R] {
override def backorder[S](f: R => S, v: T): S = {
val h = open(v)
try { f(h) } finally { implicitly[Resource[R]].close(h) }
}
}
// 右から来たものを左へ受け流すでござる
class Plant[-T, +R](assemble: T => R) extends SupplyChain[T, R] {
override def backorder[S](f: R => S, v: T): S = (f compose assemble)(v)
}
// 下請け孫請け compose でござる
class Tier[-T, +R, A](tier2: SupplyChain[T, A], tier1: SupplyChain[A, R]) extends SupplyChain[T, R] {
override def backorder[S](f: R => S, v: T): S = tier1.backorder(f, tier2.backorder(identity, v))
}
// Scalaz 向け型クラス
trait SupplyChains {
implicit val SupplyChainCategory: Category[SupplyChain] = new Category[SupplyChain] {
def id[A] = new Plant[A, A](identity)
def compose[X, Y, Z](f: SupplyChain[Y, Z], g: SupplyChain[X, Y]) = new Tier[X, Z, Y](g, f)
}
implicit val SupplyChainArrow: Arrow[SupplyChain] = new Arrow[SupplyChain] {
override val category = SupplyChainCategory
override def arrow[B, C](f: B => C) = new Plant(f)
override def first[B, C, D](a: SupplyChain[B, C]) = new SupplyChain[(B, D), (C, D)] {
override def backorder[S](f: ((C, D)) => S, v: (B, D)): S =
a.backorder(c => f(c, v._2), v._1) // 本当は LazyTuple でないと、ArrowLoop とかで困る気がする(´・ω・`)
}
override def second[B, C, D](a: SupplyChain[B, C]) = new SupplyChain[(D, B), (D, C)] {
override def backorder[S](f: ((D, C)) => S, v: (D, B)) =
a.backorder(c => f(v._1, c), v._2)
}
}
}
}
package com.github.akihiro4chawon.arm {
package object arrow extends SupplyChains {
def managed[T, R: Resource](open: T => R): SupplyChain[T, R] = new ResourceSupply(open)
}
}
import com.github.akihiro4chawon.arm.arrow._
import scalaz._
import Scalaz._
object Main extends App {
import java.io._
// なんの変哲もない部分
def copyStream(is: InputStream, os: OutputStream, buffSize: Int) {
val buff = new Array[Byte](buffSize)
var readSize = 0
while ({readSize = is.read(buff); readSize != -1})
os.write(buff, 0, readSize)
}
// Arrow のほうが本質的じゃねーの?
val openInputStream = managed(new FileInputStream(_: String): InputStream)
val openOutputStream = managed(new FileOutputStream(_: String): OutputStream)
val copyFileFunc = (copyStream(_: InputStream, _: OutputStream, 512)).tupled
val copyFileArrow = (openInputStream *** openOutputStream) >>^ copyFileFunc
// ここで実際に発動する
copyFileArrow.produce("input.txt" -> "output-arrow.txt")
// ToDo:
// ・ArrowLoop にする意味はあるのか?
// ・ArrowApply -> Monad を導出して Arrow と Monad の関係を理解する。
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment