Scalaz-Streamの基本的なクラスや概念まとめ
scalaz.concurrent.Future
Task
にかなり依存してるので、まずはこれらを理解することが重要Task
として使うことがほとんどで、Future
を直接使うことはないPar
と基本的には同じものなので、それを読むとよいjava.util.concurrent
の ConcurrentLinkedQueue
, CountDownLatch
, AtomicInteger
, AtomicBoolean
, AtomicReference
や scala.concurrent.SyncVar
などを使って実装されているscalaz.concurrent.Task
class Task[+A](val get: Future[Throwable \/ A])
というもの。FutureはScala標準のものではなく、ScalazのFuturescodec.bits.ByteVector
scodec-bits
のクラスArray[Byte]
の代わりに大抵コレが使われるProcess[F[+_], +O]
O
(2つめの型パラメータ)のシーケンスと捉えることも可能だが、実態は状態マシンであるProcess
にもあるF[_]
や O
に当てはめる型パラメータの種類によって、入力元も出力先も表すProcess
で表現するProcess1
, Process0
, Tee
, Wye
などとして使う場合を除けば F[_]
には大抵の場合 Task
が入るはず。もしくは IO
F[_]
が scalaz.Catchable
を要求するメソッドがあり、 scalaz.Catchable
のインスタンスはかなり限られているためMonadPlus
MonadPlus[({ 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
か IO
def 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]
標準出力を表現するSink
type 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生成