- versionは0.7a
- scalaz-streamではなくscalaz-concurrentにあるクラス
- scalaz-streamは、これと
Taskにかなり依存してるので、まずはこれらを理解することが重要 - Scala標準Futureと違い
- 走っている状態 は存在しない。純粋なデータ構造である
- エラー処理は行わない。別スレッドで走らせた際に例外発生したら、永遠にブロックする。つまり、実質
Taskとして使うことがほとんどで、Futureを直接使うことはない - 例の本 Scala関数型デザイン&プログラミング ―Scalazコントリビューターによる関数型徹底ガイド の7章で説明している
Parと基本的には同じものなので、それを読むとよい - 内部の低レベルな部分は
java.util.concurrentのConcurrentLinkedQueue,CountDownLatch,AtomicInteger,AtomicBoolean,AtomicReferenceやscala.concurrent.SyncVarなどを使って実装されている
class Task[+A](val get: Future[Throwable \/ A])というもの。FutureはScala標準のものではなく、ScalazのFuture- これも同じくscalaz-streamのクラスではなくscalaz-concurrentのクラス
- 依存してる
scodec-bitsのクラス - immutableなByte列
- scalaz-streamでは
Array[Byte]の代わりに大抵コレが使われる - Haskellのattoparsecのアレを真似したの?
- https://github.com/scodec/scodec-bits/blob/v1.0.6/core/src/main/scala/scodec/bits/ByteVector.scala#L1631
- http://www.serpentine.com/blog/2014/05/31/attoparsec/ C言語より速い!?とかいうやつ
- scalaz-stream内で、一番最重要で基礎となるクラス
- コレクションのように扱え、0個以上の
O(2つめの型パラメータ)のシーケンスと捉えることも可能だが、実態は状態マシンである - 事実、コレクションにあるようなメソッドの大半が
Processにもある F[_]やOに当てはめる型パラメータの種類によって、入力元も出力先も表す- つまり、IterateeにおけるEnumeratorやEnumerateeなどに相当するものも、全部
Processで表現する - 例の本 Scala関数型デザイン&プログラミング ―Scalazコントリビューターによる関数型徹底ガイド の15章で解説されているものは、ある意味これ
- ただし、本のほうは、Stackoverflow回避のためのトランポリンがされていなかったり、もう少し単純
Process1,Process0,Tee,Wyeなどとして使う場合を除けばF[_]には大抵の場合Taskが入るはず。もしくはIO- なぜかというと、
F[_]がscalaz.Catchableを要求するメソッドがあり、scalaz.Catchableのインスタンスはかなり限られているため - 無条件で
MonadPlus MonadPlus[({ type λ[α] = Process[F, α] })#λ]
- 純粋なメモリ上のシーケンスの表現?
Process0に限らないが、Nothingをあてはめたり、varianceを使ったり、良くも悪くもすべてをProcessとそのtype aliasで表現することにより、わかりずらさの一因になってる気はする
Iが入力の型、Oが出力の型になるらしい- 普通に考えると
ProcessでProcess1を表現するのは不可能に近いが、謎技術により実現されている - https://github.com/scalaz/scalaz-stream/blob/release/0.7a/src/main/scala/scalaz/stream/Process.scala#L915-L944
- 例の本にもでてきている
scalaz.Choiceやscalaz.ProfunctorのインスタンスであるChannelとは違い、副作用がない純粋な関数を表す?(このあたりの理解あまり自信がない)- これ以上うまく説明できるほどには理解できてないので、あとで
- 消費する側のやつ
Processを直接使う場合同様F[_]は大抵の場合TaskかIOdef lift[F[_], A](f: A => F[Unit]): Sink[F, A]というメソッドで生成できる- https://github.com/scalaz/scalaz-stream/blob/release/0.7a/src/main/scala/scalaz/stream/sink.scala#L6
- 標準で用意されている、
Sinkを生成するメソッド例 def chunkW(os: => OutputStream): Sink[Task,ByteVector]任意のOutputStreamをByteVectorのSinkに変換def stdOut: Sink[Task,String]標準出力を表現するSink
FはTaskやIO,Iは入力,Oは出力Process1とは違い、大抵副作用があるものの表現につかう?- この言い方で適切なのか、ちょっと自信ない
- というか、
F[_]にTaskが入ることにより、ChannelやChannelを走らせたTask自体は純粋なデータ構造で、最後にTaskを走らせる際に副作用があるので、そこを勘違いしないように - 標準で用意されている、
Channelを返すメソッド例 def chunkR(is: => InputStream): Channel[Task,Int,ByteVector]元のInputStreamからのbyte数を引数にとり、受け取ったByte数毎にわけて出力が取得できる、というもの
- 2つの入力を合成して、1つにすることを表現する関数というか状態マシン
- 標準で用意されている
Teeを返すメソッド例 def zipWith[I, I2, O](f: (I, I2) => O): Tee[I, I2, O]純粋な関数からTee生成
- TODO あとで書く
- TODO あとで書く
- TODO あとで書く
- TODO あとで書く
- TODO あとで書く
- TODO あとで書く