Scalaz-Streamの基本的なクラスや概念まとめ
scalaz.concurrent.FutureTask にかなり依存してるので、まずはこれらを理解することが重要Taskとして使うことがほとんどで、Futureを直接使うことはないPar と基本的には同じものなので、それを読むとよいjava.util.concurrent の ConcurrentLinkedQueue, CountDownLatch, AtomicInteger, AtomicBoolean, AtomicReference や scala.concurrent.SyncVar などを使って実装されているscalaz.concurrent.Taskclass Task[+A](val get: Future[Throwable \/ A]) というもの。FutureはScala標準のものではなく、ScalazのFuturescodec.bits.ByteVectorscodec-bitsのクラスArray[Byte]の代わりに大抵コレが使われるProcess[F[+_], +O]O (2つめの型パラメータ)のシーケンスと捉えることも可能だが、実態は状態マシンであるProcessにもあるF[_] や O に当てはめる型パラメータの種類によって、入力元も出力先も表すProcess で表現するProcess1, Process0, Tee, Wye などとして使う場合を除けば F[_] には大抵の場合 Task が入るはず。もしくは IOF[_] が scalaz.Catchable を要求するメソッドがあり、 scalaz.Catchable のインスタンスはかなり限られているためMonadPlusMonadPlus[({ type λ[α] = Process[F, α] })#λ]type Process0[+O] = Process[Nothing,O]Process0 に限らないが、Nothingをあてはめたり、varianceを使ったり、良くも悪くもすべてをProcessとそのtype aliasで表現することにより、わかりずらさの一因になってる気はするtype Process1[-I,+O] = Process[Env[I,Any]#Is, O]I が入力の型、 O が出力の型になるらしいProcess で Process1 を表現するのは不可能に近いが、謎技術により実現されているscalaz.Choice や scalaz.Profunctor のインスタンスであるChannel とは違い、副作用がない純粋な関数を表す?(このあたりの理解あまり自信がない)type Sink[+F[_],-O] = Process[F, O => F[Unit]]Process を直接使う場合同様 F[_] は大抵の場合 Task か IOdef lift[F[_], A](f: A => F[Unit]): Sink[F, A] というメソッドで生成できるSinkを生成するメソッド例def chunkW(os: => OutputStream): Sink[Task,ByteVector] 任意のOutputStreamをByteVectorのSinkに変換def stdOut: Sink[Task,String] 標準出力を表現するSinktype Channel[+F[_],-I,O] = Process[F, I => F[O]]F は Task や IO, I は入力, O は出力Process1 とは違い、大抵副作用があるものの表現につかう?F[_]にTaskが入ることにより、 Channel や Channel を走らせた Task 自体は純粋なデータ構造で、最後に Task を走らせる際に副作用があるので、そこを勘違いしないようにChannel を返すメソッド例def chunkR(is: => InputStream): Channel[Task,Int,ByteVector] 元のInputStreamからのbyte数を引数にとり、受け取ったByte数毎にわけて出力が取得できる、というものtype Tee[-I,-I2,+O] = Process[Env[I,I2]#T, O]Tee を返すメソッド例def zipWith[I, I2, O](f: (I, I2) => O): Tee[I, I2, O] 純粋な関数からTee生成