2015年6月13日土曜日

scala関数型デザイン&プログラミング P122

前提となるjavaの並列処理の知識もないので、なかなか先に進めない。
def sum(ints:IndexdSeq[Int]): Int=
 if(ints.size<=1)
 ints headOption getOreElse 0
else {
 val (l,r)=ints.splitAt(ints,length/2)
 val sumL: Par[Int]=Par.unit(sum(l))
 val sumR:Par[Int]=Par.unit(sum(r))
 Par.get(sumL)+Par.get(sumR)
}
Par.get(Par.unit(sum(l)))+Par.get(Par.unit(sum(r)))とみなした場合どうなるか、考察している。
 結局は、unitが引数の評価をすぐに開始した場合(その評価は並列で別々に処理されている)、その評価が完了するのを(両方の処理が終わってもどってくるまで)getが待機することになるということ。
 だから、getの呼び出しを避けるか、最後の最後まで呼び出しを遅らせるほうがいい。非同期計算が終了するのをまたずに、それらを結合できるようにしたほうがいい。(副作用がない、参照透過性が失われない構造にするために?)ということか?
改良版が示されている。getでIntを呼び出すことは避けるため、sumでPar[Int]を呼び出している。
def sum(ints:IndexSeq[Int]):Par[Int]=
 if(ints.size<=1)
  Par.unit(ints.headOption getOrElse 0)
 else {
 val (l,r)=ints.splitAt(ints,length/2)
 Par.map2(sum(l),sum(r))(_+_)
}
Exercise7.1 Par.map2は2つの並列計算の結果を統合する新しい高階関数である。そのシグネチャはどのようなものになるか。Intにのみ対応すると想定せず、できるだけ汎用的なシグネチャを示せ。
 de Par.map2(Par[A],Par[A])((A,A)=>A):Par[A]
としてみたが、正解は
/* def map2[A,B,C](a: Par[A], b: Par[B])(f: (A,B) => C): Par[C] */
だった。必ずしもすべてAにせず、もっと汎用的にしなさいということのようだ。

0 件のコメント:

コメントを投稿