有限次元の線形空間では二つのノルム||・||1と||・||2があるとき、ある定数C>0が存在して
1/C||x||1≦||x||2≦C||x||1
をみたすことを示せ。
解答では 右辺を示している。超入門というタイトルだが、自分にとっては難しい。
e1、,,enを基底とする。独立性から
δ= inf ||c1e1+.......+cnen||1
Σ|ci|=1
とおくと、δ>0である。
(∵独立性から δ=0なら∀iについてci=0 、対偶を考えると Σ|ci|が0でないから
∃ciが0でない。よってδ>0)
任意のxについて x=Σaieiと表せるので
||x||2=||Σaiei||2
≦max||ei||2×Σ|ai|
(∵ ノルムの定義より、三角不等式 ||c1e1+c2e2+...||<=||c1e1||+||c2e2||+....
=|c1|||e1||+|c2|||e2||...さらにeiのmaxをすべての項かける)
=max||ei||2×Σ|ai|×inf ||Σciei||1×1/δ (?解答は≦となっていたが、=のように思えるが)
Σ|ci|=1
≦max||ei||2×1/δ×||x||1
(∵ Σ|ai|×inf ||Σciei|| = inf ||ΣAciei|| ここでΣ|ai|=Aとおいた。
Σ|ci|=1 Σ|ci|=1
=inf ||ΣAciei||
Σ|Aci|=A (∵ A×Σ|ci|=A×1 )
ここで、AciをXiとおくと
=inf ||ΣXiei||
Σ|Xi|=A A=Σ|ai|だから
=inf |Σ|Xiei||
Σ|Xi|=Σ|ai|
Xi=aiのときは、 ||ΣXiei|| を満たすが、 この式の下限とは限らない。
Σ|Xi|=Σ|ai|
したがって、
≦||Σaiei||=||x||)
これでいいのだろうか?
2015年12月29日火曜日
2015年12月23日水曜日
5600Cの紙詰まり
NECのカラーレーザープリンタが紙詰まりしてしまい、無理にとろうとしたら、破れた紙片が、とれないところに残ってしまい、どうすることもできなくなってしまった。最近のプリンタは、安くなった半面ちょっとしたトラブルには苦労することが多い。
どうやら、ネットで調べたら、蓋の外し方が出ていたので、そのとおりやってみたら解決できた。
以下のサイトに助けられました。
http://blogs.itmedia.co.jp/tani/2014/12/29_1.html
どうやら、ネットで調べたら、蓋の外し方が出ていたので、そのとおりやってみたら解決できた。
以下のサイトに助けられました。
http://blogs.itmedia.co.jp/tani/2014/12/29_1.html
2015年12月13日日曜日
圏論 P20
任意のモノイドNは台集合|N|をもち、任意の準同型写像f:N→Mは台写像|f|:|N|→|M|をもつ。これが関手であることは容易に分かり、忘却関手と呼ばれる。
ここでは、Nがたとえば{a,b,c..}なら、|N|が{ab,ac,,,,}といった連結を表すことになるのだろうか。
ここでの忘却関手は、f:N→Mという圏(Mon)から|f|:|N|→|M|という圏(Sets)への関手ということだろうか。
ここでは、Nがたとえば{a,b,c..}なら、|N|が{ab,ac,,,,}といった連結を表すことになるのだろうか。
ここでの忘却関手は、f:N→Mという圏(Mon)から|f|:|N|→|M|という圏(Sets)への関手ということだろうか。
2015年11月28日土曜日
圏論勉強会第7回
(T,in)がF始代数ならば
(|in|)=1T(反射則)
またh∘f=g∘F(h) ①が成り立つならば
h∘(|f|)=(|g|) ② (融合則)
sum∘filter(even)を一つのfoldrで表せ。
まず
p(a,as)= cons(a,as) (even(a)=trueの時)
{ as (それ以外)
とするとfilter(even)=(|[nil,p]|)となります。
このfilter(even)=(|[nil,p]|)が②の(|f|)に対応する
よってsum∘[nil,p]=[c,g]∘(11+1A×sum) ③ を満たすc,gを見つければ融合則が使えます。
①に対応する式が③ また、[nil,p]が①のfに対応している。 sumはhに対応。
これをpointwiseな等式に書き直すとまずc=sum(nil)=0であり,
∵③式の左の要素どうしが等しいことから
g(a,sum(as))= sum(cons(a,as))=a+sum(as) (even(a)=trueの時)
{ sum(as) (それ以外)
が成り立てば良いので,
∵③式の右の要素が等しいから p適用後sum適用つまり、sum(p(a,as)) =sum適用後g適用つまり g(a、sum(as)) ということか
g(a,x)= a+x (even(a)=trueの時)
{ x (それ以外)
とすれば良いです。すなわち(|[0,g]|)=foldr(g,0)が求める関数です。
(|in|)=1T(反射則)
またh∘f=g∘F(h) ①が成り立つならば
h∘(|f|)=(|g|) ② (融合則)
sum∘filter(even)を一つのfoldrで表せ。
まず
p(a,as)= cons(a,as) (even(a)=trueの時)
{ as (それ以外)
とするとfilter(even)=(|[nil,p]|)となります。
このfilter(even)=(|[nil,p]|)が②の(|f|)に対応する
よってsum∘[nil,p]=[c,g]∘(11+1A×sum) ③ を満たすc,gを見つければ融合則が使えます。
①に対応する式が③ また、[nil,p]が①のfに対応している。 sumはhに対応。
これをpointwiseな等式に書き直すとまずc=sum(nil)=0であり,
∵③式の左の要素どうしが等しいことから
g(a,sum(as))= sum(cons(a,as))=a+sum(as) (even(a)=trueの時)
{ sum(as) (それ以外)
が成り立てば良いので,
∵③式の右の要素が等しいから p適用後sum適用つまり、sum(p(a,as)) =sum適用後g適用つまり g(a、sum(as)) ということか
g(a,x)= a+x (even(a)=trueの時)
{ x (それ以外)
とすれば良いです。すなわち(|[0,g]|)=foldr(g,0)が求める関数です。
2015年11月4日水曜日
圏論 P19
Cの対象Cのもとでの余スライス圏C/Cとは、対象としてdom(f)=CをみたすCのすべての射fをもち、f:C→Xからf’:C→X'への射はh・f=f’となる射h:X→X’である。さて、スライス圏の定義から、余スライス圏の定義の残りの部分を実行してほしい。スライス圏および双対構造の用語により、余スライス圏はどのように定義されるであろうか?
h
X → X’
f↖ ↗f’
C
C/Cでは、f、f’が対象 hが射 ?
例1.8 点付き集合の圏Sets*は 与えられた点a∈Aをもつ 集合Aからなり、射f:(A,a)→(B,b)は’点’を保つ。すなわちf(a)=bをみたす写像f:A→Bである。これは、一つの要素からなる任意の集合1={*}の’もとで’、集合の余スライス圏と同型である。
Sets*≅1/Sets
実際、写像a:1→Aは要素a(*)=aに一意に対応し、射f:(A,a)→(B,b)はちょうど次の可換三角形に対応する。 a
1 → A
b↘ ↓f
B
わかりやすいサイトです。参考にさせていただきました。
h
X → X’
f↖ ↗f’
C
C/Cでは、f、f’が対象 hが射 ?
例1.8 点付き集合の圏Sets*は 与えられた点a∈Aをもつ 集合Aからなり、射f:(A,a)→(B,b)は’点’を保つ。すなわちf(a)=bをみたす写像f:A→Bである。これは、一つの要素からなる任意の集合1={*}の’もとで’、集合の余スライス圏と同型である。
Sets*≅1/Sets
実際、写像a:1→Aは要素a(*)=aに一意に対応し、射f:(A,a)→(B,b)はちょうど次の可換三角形に対応する。 a
1 → A
b↘ ↓f
B
わかりやすいサイトです。参考にさせていただきました。
2015年10月31日土曜日
圏論 P17
3 Cの射の圏 C→ はCの射を対象としてもち、f:A→B から f’:A’→B’へのC→の射gは
可換正方形
g1
A→A’
f ↓ ↓f’
B→B’
g2
である。ここで、g1とg2はCの射である。すなわち、このような射はCの射の対g=(g1,g2)であり
g2・f=f'・g1
をみたす。 対象f:A→B上の恒等射1fは対(1A,1B)である。射の合成は成分ごと行われる。
(h1,h2)・(g1,g2)=(h1・g1,h2・g2)
適切な可換図式が描くことにより、これがうまくいくことを確かめよ。
g1 h1
A→A’→A''
f ↓ ↓f’ ↓f''
B→B’→B''
g2 h2
g=(g1,g2)とh=(h1,h2)はC→の射で、C→の対象は、f,f',f'' といったところか?
二つの関手が存在することをみてほしい。
dom cod
C ← C→ → C
ちょっと違うかもしれないけれど、たとえばニュアンスとしてはこんな感じだろうか?
cod(g:f→f')=cod(g):cod(f)→cod(f')=g2:B→B'
dom(g:f→f')=dom(g):dom(f)→dom(f')=g1:A→A'
可換正方形
g1
A→A’
f ↓ ↓f’
B→B’
g2
である。ここで、g1とg2はCの射である。すなわち、このような射はCの射の対g=(g1,g2)であり
g2・f=f'・g1
をみたす。 対象f:A→B上の恒等射1fは対(1A,1B)である。射の合成は成分ごと行われる。
(h1,h2)・(g1,g2)=(h1・g1,h2・g2)
適切な可換図式が描くことにより、これがうまくいくことを確かめよ。
g1 h1
A→A’→A''
f ↓ ↓f’ ↓f''
B→B’→B''
g2 h2
g=(g1,g2)とh=(h1,h2)はC→の射で、C→の対象は、f,f',f'' といったところか?
二つの関手が存在することをみてほしい。
dom cod
C ← C→ → C
ちょっと違うかもしれないけれど、たとえばニュアンスとしてはこんな感じだろうか?
cod(g:f→f')=cod(g):cod(f)→cod(f')=g2:B→B'
dom(g:f→f')=dom(g):dom(f)→dom(f')=g1:A→A'
2015年10月29日木曜日
圏論 原著第2版 P15
圏論のさわりを少し読んでみた。群論の抽象度をさらに上げたもの という感じだろうか、はっきりいってわかりにくい。読み始めてさっそく最初のほうでつまづく。
∵(概要)Cのケイリー表現Cを次の具象的な圏として定義せよ
・対象は、∀C∈Cに対して C={f∈C|cod(f)=C} という形の集合である。
・射は、 Cのg:C→D に対する写像 g:C→D であり
C∋∀f:X→C に対してg(f)=g・f により定義される。
X
f↓ ↘g・f
C→D
g
D={射∈C|cod(射)=D} この射に該当するのはg・fということ?
gやC、Dは、射(写像)や対象(集合)は、いわゆるケイリー表現と呼ばれるもののようだ。
C、Dは 実際は射の集合で その写像がgということだろうか?
ケイリー表現というのは、すべての要素g∈Gに対して、置換g:G→Gを得ることができることを意味する
ケイリー表現というのは、すべての要素g∈Gに対して、置換g:G→Gを得ることができることを意味する
2015年10月26日月曜日
Acrobits Softphone
スマホのネット電話はバッテリー消費が多くて、間歇動作させていたが、やはり不便さは残る。
何かいい方法はないかと、ソフトを探していたらAcrobits Softphoneというアプリを見つけた。これだと、待ち受け時のバッテリー消費がかなり抑えられており、ネット電話には最適なようだ。バッテリーの持ちが非常によくなり、待ち受けだけなら充電なしで数日程度は持つことになる。
699円と有料であるが、バッテリー対策がされている最新機種に買い替えることに比べれば少ない投資である。
何かいい方法はないかと、ソフトを探していたらAcrobits Softphoneというアプリを見つけた。これだと、待ち受け時のバッテリー消費がかなり抑えられており、ネット電話には最適なようだ。バッテリーの持ちが非常によくなり、待ち受けだけなら充電なしで数日程度は持つことになる。
699円と有料であるが、バッテリー対策がされている最新機種に買い替えることに比べれば少ない投資である。
2015年10月19日月曜日
圏論勉強会(YouTube)
Youtubeで、圏論勉強会の動画があったので、見てみた。ネットで読むより概観、イメージがつかみやすい。Haskellも使いながら圏論の初歩との関連を説明してくれている。細かいところでまだまだ理解不足のところもあるけれど、書籍などいきなり読むよりは入りやすい気がします。
第一回:対、AND集合、最小値などがじつは圏論では共通性があるということなど興味深く拝聴させていただきました。最後のほうで函手、自然変換などの説明があります。
第二回:モノイドについての説明です。最初のほうでfoldmap、endomorphismについて説明しています。各回は2時間、連続聴講はちょっときつい。とりあえず、今回は半分程度視聴して終わり。
第一回:対、AND集合、最小値などがじつは圏論では共通性があるということなど興味深く拝聴させていただきました。最後のほうで函手、自然変換などの説明があります。
第二回:モノイドについての説明です。最初のほうでfoldmap、endomorphismについて説明しています。各回は2時間、連続聴講はちょっときつい。とりあえず、今回は半分程度視聴して終わり。
2015年10月14日水曜日
Windowsサーバでアクセス制限をバッチファイルで一括処理
NFTSアクセス制限は、GUIでも設定できるが、一括処理はやはり、バッチファイルの利用が効率的である。
エクセル等で、編集してテキスト保存したものをバッチファイルで利用するといいようだ。
たとえば、
echo y|cacls d:\test /E /P username:W
などとすれば、testフォルダに対して、特定のユーザーの書き込み権限を与えられる。
エクセル等で、編集してテキスト保存したものをバッチファイルで利用するといいようだ。
たとえば、
echo y|cacls d:\test /E /P username:W
などとすれば、testフォルダに対して、特定のユーザーの書き込み権限を与えられる。
2015年10月11日日曜日
LINQについて
.NETではLINQが使え、関数型プログラミングに近いことができるようになっている。
http://yohshiy.blog.fc2.com/blog-entry-274.html
を参考にさせていただくと
scalaやHaskellなどと変わりなく、カリー化、遅延処理、map,foldといった機能がそろっていることがよくわかります。
ということは、完全とはいかないまでもscalaやHaskellでなくても、.NETで関数型っぽいプログラミングが、ある程度できるということになりそうです。
ただ、副作用のないものにするということには注意しなければならないのだと思いますが。。
そこまで意識がいくまでにはもう少し修行が必要なようです。
http://yohshiy.blog.fc2.com/blog-entry-274.html
を参考にさせていただくと
scalaやHaskellなどと変わりなく、カリー化、遅延処理、map,foldといった機能がそろっていることがよくわかります。
ということは、完全とはいかないまでもscalaやHaskellでなくても、.NETで関数型っぽいプログラミングが、ある程度できるということになりそうです。
ただ、副作用のないものにするということには注意しなければならないのだと思いますが。。
そこまで意識がいくまでにはもう少し修行が必要なようです。
2015年9月17日木曜日
USB使用制限システムについて
職場で某会社のUSBメモリ等の使用を制限できるシステムソフトを使っているが、登録を簡単にするためのソフトを作ってみた。インポート、エクスポートの機能によりCSVデータをエクセルで編集するようにと、マニュアルには出ているが。USBメモリのシリアル番号はじめ、各種番号の取得が、エクセルでは面倒で、別ソフトを使う必要がある。そこで、番号取得の機能や編集機能をひとまとめにした自作ソフトを作ってみた。なんとか、実用にはこぎつけた。あいかわらず、Vb.netを使っている。でも、意外に最近のVb.netにはLINQなど、高階関数っぽい機能など、関数プログラミングに近い機能もある。うまく活用すると、けっこう楽にプログラムができるようになっている。
たとえば、Listbox(CSVデータの各行をセット)をある関数を適用したもので、ソートするとすると、こんな感じに簡潔にできるようだ。
Dim gyoh() As String
gyoh = ArrayList.Adapter(ListBox1.Items).ToArray(GetType(String))
'Linqで並び替え
Dim query = gyoh.OrderBy(Function(s) serN(s))
ListBox1.Items.Clear()
For Each gy As Object In query
ListBox1.Items.Add(gy.ToString)
Next
Private Function serN(ByVal gyo As String) As String
Dim sst() As String
sst = gyo.Split(",")
serN = sst(5)
End Function
たとえば、Listbox(CSVデータの各行をセット)をある関数を適用したもので、ソートするとすると、こんな感じに簡潔にできるようだ。
Dim gyoh() As String
gyoh = ArrayList.Adapter(ListBox1.Items).ToArray(GetType(String))
'Linqで並び替え
Dim query = gyoh.OrderBy(Function(s) serN(s))
ListBox1.Items.Clear()
For Each gy As Object In query
ListBox1.Items.Add(gy.ToString)
Next
Private Function serN(ByVal gyo As String) As String
Dim sst() As String
sst = gyo.Split(",")
serN = sst(5)
End Function
2015年9月13日日曜日
PostgreSqlにslick使用 scala
Herokuにslick利用してみようと試してみているが、けっこう手こずる。activator uiから試してもうまくいかなかったので、以下からgit cloneさせていただいたところローカルやHerokuでうまく動作するところまではこぎつけた。
ローカルでは
psql -U postgres
#create database play_heroku_seed;
で、データベースを作成し
application.confに
db.default.user=ユーザー名
db.default.password="パスワード"
とすればOKだった。
Herokuにはすにで、postgrsqlが動いているので
heroku login
heroku create
git add .
git push heroku master
heroku open
******************************************
ユーザー名とパスワードを設定すると、ローカルではいいが、Herokuではやはり
だめだったので、ローカルでも環境変数DATABASE_URLを変更してみたらOkだった。
postgres://[username]:[password]@[host]:[port]/[database]
Herokuにはすにで、postgrsqlが動いているので
heroku login
heroku create
git add .
git push heroku master
heroku open
******************************************
ユーザー名とパスワードを設定すると、ローカルではいいが、Herokuではやはり
だめだったので、ローカルでも環境変数DATABASE_URLを変更してみたらOkだった。
postgres://[username]:[password]@[host]:[port]/[database]
2015年9月12日土曜日
herokuを使ってみたが heroku localがうまくいかない
説明どおり動かしてみたが、
heroku local web -f Procfile.windowsがうまく動作しない。
どうやらProcfile.windowsの記述が関係あることらしいことはわかる。
でも、Windows用のファイルなんだから、変更は不要と思ったのだがそうでなかった。
web: target/universal/stage/bin/play-getting-started.batを
web: target\universal\stage\bin\play-getting-started.batとしたらうまくいった。
こういうちょっとしたことが、なかなかわかりにくい。
ちなみに、playが入っていればactivator runでもLocalで実行できるが
heroku local web -f Procfile.windowsがうまく動作しない。
どうやらProcfile.windowsの記述が関係あることらしいことはわかる。
でも、Windows用のファイルなんだから、変更は不要と思ったのだがそうでなかった。
web: target/universal/stage/bin/play-getting-started.batを
web: target\universal\stage\bin\play-getting-started.batとしたらうまくいった。
こういうちょっとしたことが、なかなかわかりにくい。
ちなみに、playが入っていればactivator runでもLocalで実行できるが
2015年9月10日木曜日
人工知能
最近、人工知能(機械学習)の進歩が人間の仕事の仕事を奪うかもしれない、という話題がよく聞かれる。
チェスや将棋のように、ルール(データ入力)も目標もはっきりしているものは、機械にかなわなくなりそうなのは、なんとなくわかるけれど、仕事一般はそうだろうか。
何らかの処理をするためには、必ずデータの入力が必要だが、これが意外と大変なのでないだろうか。当分の間は、人間が間に入らないと処理の前提となるデータを機械に伝えられない。むしろ、その手間は、以前より複雑化しているようにも思える。
ビッグデータのようなネットから集められる情報を入力するのはいいとしても、細かいニュアンスを伝えるには、細かい処理や対話が必要だろうから、当面の人間の仕事はなくならないようにも思える。対話で内容を伝えるより、従来通り設定データのようなもので伝えたほうが正確で速いので、そういった作業を行う人間の仕事は簡単にはなくならないようにも思う。
もっともコンピュータが、人間のような5感センサーと人体を持つようになり(要するにロボット)、人間と同様の関わり方をするようになれば、人間に近い仕事をするようになる可能性はあるかもしれない。ただ、脳の認知・思考機能や体の働きにはまだまだ解明されていないこともあるようなので、近いものはできるかもしれないが、おそらく機械と人間では、どこかしら違うところが出てくるのでないだろうか。その違いがある限り、人間の仕事はなくなることはないような気がする。
http://techtarget.itmedia.co.jp/tt/news/1511/02/news04.html
チェスや将棋のように、ルール(データ入力)も目標もはっきりしているものは、機械にかなわなくなりそうなのは、なんとなくわかるけれど、仕事一般はそうだろうか。
何らかの処理をするためには、必ずデータの入力が必要だが、これが意外と大変なのでないだろうか。当分の間は、人間が間に入らないと処理の前提となるデータを機械に伝えられない。むしろ、その手間は、以前より複雑化しているようにも思える。
ビッグデータのようなネットから集められる情報を入力するのはいいとしても、細かいニュアンスを伝えるには、細かい処理や対話が必要だろうから、当面の人間の仕事はなくならないようにも思える。対話で内容を伝えるより、従来通り設定データのようなもので伝えたほうが正確で速いので、そういった作業を行う人間の仕事は簡単にはなくならないようにも思う。
もっともコンピュータが、人間のような5感センサーと人体を持つようになり(要するにロボット)、人間と同様の関わり方をするようになれば、人間に近い仕事をするようになる可能性はあるかもしれない。ただ、脳の認知・思考機能や体の働きにはまだまだ解明されていないこともあるようなので、近いものはできるかもしれないが、おそらく機械と人間では、どこかしら違うところが出てくるのでないだろうか。その違いがある限り、人間の仕事はなくなることはないような気がする。
http://techtarget.itmedia.co.jp/tt/news/1511/02/news04.html
2015年8月22日土曜日
Webの高速化
グループウエアは、jqueryなど機能を増やすとその分どうしても遅くなっていくようだ。高速化のためには、.jsや.cssなどを圧縮するとか、一つのファイルにまとめるとかいろいろ細かい調整があるようだ。あと、tomcat7にはExpiresFilterという機能を使って、静的コンテンツはキャッシュにできること、テキストデータは圧縮をかけること(tomcatのfilter)を知った。早速試してみたい。
というか、もとはといえばjspのサイズが大きくなってしまったのが原因。こんなことになるんだったら、もう少しファイルを切り分けるとかすればよかった。
Gtmetrix,yslowなど使うと、どこが遅くなる原因かつかめるようだ。
****************
その後、いろいろ試してみたが、JAVAのガベージコレクションの問題もあるのかと思い、CATALINA_OPTS="-server -Xms512m -Xmx1024m 云々の設定も試してみた。Ubuntuの場合
/etc/environmentに環境変数を設定できるようだ。
いちおう、やれることはすべてやってみたが、PCの性能によってやはりレスポンスの差はどうしてもあるようだ。シングルコアのメモリが1GBにも満たないものだと、大きなWEBファイルのせいか?(機能を盛り込みすぎたか)最大で10秒ほど待たされてしまう。それより、ちょっぴりCPUとメモリがよいPCで、最大5秒前後。スムーズな時は、1秒もかからず反応するのだけど、この違いは何なのか、いまひとつはっきりわからない。
グループウエアというのは、最初のうちは、機能がいろいろあって便利だといいだろうと思っていたが、実際にはレスポンスの良さが、ユーザーにとってはより重要なことなのかもしれない。
というか、もとはといえばjspのサイズが大きくなってしまったのが原因。こんなことになるんだったら、もう少しファイルを切り分けるとかすればよかった。
Gtmetrix,yslowなど使うと、どこが遅くなる原因かつかめるようだ。
****************
その後、いろいろ試してみたが、JAVAのガベージコレクションの問題もあるのかと思い、CATALINA_OPTS="-server -Xms512m -Xmx1024m 云々の設定も試してみた。Ubuntuの場合
/etc/environmentに環境変数を設定できるようだ。
いちおう、やれることはすべてやってみたが、PCの性能によってやはりレスポンスの差はどうしてもあるようだ。シングルコアのメモリが1GBにも満たないものだと、大きなWEBファイルのせいか?(機能を盛り込みすぎたか)最大で10秒ほど待たされてしまう。それより、ちょっぴりCPUとメモリがよいPCで、最大5秒前後。スムーズな時は、1秒もかからず反応するのだけど、この違いは何なのか、いまひとつはっきりわからない。
グループウエアというのは、最初のうちは、機能がいろいろあって便利だといいだろうと思っていたが、実際にはレスポンスの良さが、ユーザーにとってはより重要なことなのかもしれない。
2015年8月17日月曜日
slickの設定
ネット上の情報をもとに、slickの設定しようとしたが、うまくいかない。どうやら、バージョンをplayに合わせる必要があるようだ。最新版のバージョンを調べて、設定してみたら、なんとかなった。
以下build.sbtの中身
libraryDependencies ++= Seq(
jdbc,
cache,
ws,
specs2 % Test,
"com.typesafe.slick" %% "slick" % "3.0.2",
"org.slf4j" % "slf4j-nop" % "1.6.4",
"com.typesafe.play" %% "play-slick" % "1.0.1"
)
このあと
activator update
activator eclipse
を実行することで、eclipseでの編集ができるようになるようだ
*************
このあと、ネットを参考に、サンプルプログラムを試してみるが、うまくコンパイルできない。
import play.api.db.slick.Config.driver.simple._と
あるけれど、実際には
import slick.driver.H2Driver.api._
import slick.lifted._
などが必要?でも、slickのバージョンが少し違うといろいろなところで、はじかれてしまう?依存関係がいまいちよくわからない。まだまだ実用的なソフトをscalaでつくるには壁がありそうだ。
以下build.sbtの中身
libraryDependencies ++= Seq(
jdbc,
cache,
ws,
specs2 % Test,
"com.typesafe.slick" %% "slick" % "3.0.2",
"org.slf4j" % "slf4j-nop" % "1.6.4",
"com.typesafe.play" %% "play-slick" % "1.0.1"
)
このあと
activator update
activator eclipse
を実行することで、eclipseでの編集ができるようになるようだ
*************
このあと、ネットを参考に、サンプルプログラムを試してみるが、うまくコンパイルできない。
import play.api.db.slick.Config.driver.simple._と
あるけれど、実際には
import slick.driver.H2Driver.api._
import slick.lifted._
などが必要?でも、slickのバージョンが少し違うといろいろなところで、はじかれてしまう?依存関係がいまいちよくわからない。まだまだ実用的なソフトをscalaでつくるには壁がありそうだ。
2015年8月16日日曜日
今年の畑の状況
今年は、小玉スイカを試しに植えてみた。つるの伸びがすごい。1畝に1株しか植えなかったのだが、それでも別の畝のトマトまで越境していく始末。でも、1株から10個近くとれたので、十分もとはとれた。ナスは、昨年ほどでないが、平年並み。トマトも順調で、食べきれないので、ジューサーでトマトジュースにしている。
小玉スイカとダダチャ豆の収穫が終わり空いたところには、これから大根を植える予定。残ったのはインゲン、トマト、ナス、ゴーヤ。トマトはそろそろおしまいだが、ゴーヤは今が最盛期。
小玉スイカとダダチャ豆の収穫が終わり空いたところには、これから大根を植える予定。残ったのはインゲン、トマト、ナス、ゴーヤ。トマトはそろそろおしまいだが、ゴーヤは今が最盛期。
2015年8月15日土曜日
scala playをeclipseで使ってみる
scalaでplayを利用してみた。コマンドラインからは、ネットの情報でなんとか使えるようになったが、eclipseの設定については、試行錯誤が必要なようだ。
とりあえず、以下のリンクを参考にさせていただいた。
http://qiita.com/Orfeus/items/84635a5ff86ba093f408
・java、javac、activatorのフォルダのパスは通しておいた。playのminimum版を解凍。
・やはりaddSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "4.0.0")をplugin.sbtの中に追加しないとだめだった。
・activator newで6)play-scalaを選択 適当な名前(今回はtest)をつける cd test
でactivator runで 実行できることを確認する。
・activator compileを行ってから、activator eclipseでプロジェクトファイル作成ができるようだ。そしてeclipseでimport と、ここまでは前回の復習。
・緑に白抜き三角と鞄のアイコンのわきの▼をクリック>外部ツールの構成で、プログラムを右クリック>新規>ロケーションで、activator.batを選択、作業ディレクトリは、同じフォルダ指定、引数にrunとしてみたら、いちおう動いたようだ。
が、止め方がまだよくわからない。コマンドプロンプトであれば、CTRL+Dで止めるのだが、、、。
ソースを修正して、再コンパイルするとエラーとなる。ただ、再表示させると、自動的にリロードしてくれるので、修正は反映されるようだが。。。
とりあえず、以下のリンクを参考にさせていただいた。
http://qiita.com/Orfeus/items/84635a5ff86ba093f408
・java、javac、activatorのフォルダのパスは通しておいた。playのminimum版を解凍。
・やはりaddSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "4.0.0")をplugin.sbtの中に追加しないとだめだった。
・activator newで6)play-scalaを選択 適当な名前(今回はtest)をつける cd test
でactivator runで 実行できることを確認する。
・activator compileを行ってから、activator eclipseでプロジェクトファイル作成ができるようだ。そしてeclipseでimport と、ここまでは前回の復習。
・緑に白抜き三角と鞄のアイコンのわきの▼をクリック>外部ツールの構成で、プログラムを右クリック>新規>ロケーションで、activator.batを選択、作業ディレクトリは、同じフォルダ指定、引数にrunとしてみたら、いちおう動いたようだ。
が、止め方がまだよくわからない。コマンドプロンプトであれば、CTRL+Dで止めるのだが、、、。
ソースを修正して、再コンパイルするとエラーとなる。ただ、再表示させると、自動的にリロードしてくれるので、修正は反映されるようだが。。。
2015年8月11日火曜日
Vb.net メニューアイテムを動的な配列にしてみた
メニューアイテムは通常は、動的に変化させてつかうことは少ないかもしれないが、設定ファイルサイズに合わせて、動的に項目数を変化させられれば便利かと思い、試してみました。
Public Class Form1
.......
Dim snm() As String
Dim sumax as Integer
Dim DpItem As ToolStripMenuItem() = New ToolStripMenuItem() {}
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
...............ここで、sumax行のデータをファイル(SURLP)から読み出し、snm()がデータだとすれば
Try
snm = Split(SURLP, vbCrLf)
sumax = snm.Length
ReDim DpItem(sumax)
For i As Integer = 0 To sumax - 1
..............
ToolStripMenuItem4.DropDownItems.Add(snm(i))
DpItem(i) = ToolStripMenuItem4.DropDownItems(i)
AddHandler DpItem(i).Click, AddressOf DpItem_Click
Next
...........
Try
......snumをファイルから読み出す
For i As Integer = 0 To sumax - 1
If i = Int(snum) Then
DpItem(i).Checked = True
Else
DpItem(i).Checked = False
End If
Next
Catch ex As Exception
End Try
End Sub
Private Sub DpItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
Dim ic As Integer
For i As Integer = 0 To sumax - 1
If sender.ToString = snm(i) Then
Try
....ここでiをファイルに保存
ic = i
Catch ex As Exception
MsgBox(snm(i) + "ログインのショートカットがありません")
End Try
End If
Next
For i As Integer = 0 To sumax - 1
If i = ic Then
DpItem(i).Checked = True
Else
DpItem(i).Checked = False
End If
Next
End Sub
Public Class Form1
.......
Dim snm() As String
Dim sumax as Integer
Dim DpItem As ToolStripMenuItem() = New ToolStripMenuItem() {}
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
...............ここで、sumax行のデータをファイル(SURLP)から読み出し、snm()がデータだとすれば
Try
snm = Split(SURLP, vbCrLf)
sumax = snm.Length
ReDim DpItem(sumax)
For i As Integer = 0 To sumax - 1
..............
ToolStripMenuItem4.DropDownItems.Add(snm(i))
DpItem(i) = ToolStripMenuItem4.DropDownItems(i)
AddHandler DpItem(i).Click, AddressOf DpItem_Click
Next
...........
Try
......snumをファイルから読み出す
For i As Integer = 0 To sumax - 1
If i = Int(snum) Then
DpItem(i).Checked = True
Else
DpItem(i).Checked = False
End If
Next
Catch ex As Exception
End Try
End Sub
Private Sub DpItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
Dim ic As Integer
For i As Integer = 0 To sumax - 1
If sender.ToString = snm(i) Then
Try
....ここでiをファイルに保存
ic = i
Catch ex As Exception
MsgBox(snm(i) + "ログインのショートカットがありません")
End Try
End If
Next
For i As Integer = 0 To sumax - 1
If i = ic Then
DpItem(i).Checked = True
Else
DpItem(i).Checked = False
End If
Next
End Sub
2015年8月5日水曜日
Poiでエクセルデータ読み込みの工夫(グループウエア)
グループウエアへのスケジュールデータをpoiを使って、ふだん使っているエクセルデータから読むようにしている。WEBで入力したり、インポートしたりという手間を省くためだ。ただ、残念ながら、データベースにくらべ、読み込みにどうしても負荷がかかるようだ。(これも、グループウエアが遅くなる原因か?)
そこで、キャッシュデータを使う方法を考えてみた。
public void doGet(..................
Calendar calendar = Calendar.getInstance();
int hour = calendar.get(Calendar.HOUR_OF_DAY);
int minute = calendar.get(Calendar.MINUTE);
int cmin=hour*60+minute;//現在時刻 整数値
ServletContext sc = getServletContext();
String ptime = (String)sc.getAttribute("time");//前回のキャッシュ時の時刻
String Cachex=(String)sc.getAttribute("cache");
if(cmin>=Integer.parseInt(ptime)&&cmin<=5+Integer.parseInt(ptime) && Cachex!=null){
//前回のキャッシュ作成から5分以上経過してないときは、キャッシュ利用
out.print(Cachex);
return;
}
Cache=ここで、poiの機能を使って読み取った 表示させたいデータ をセット
..............................................
ServletContext scc = getServletContext();
scc.setAttribute("cache", Cache);
String pptime="";
pptime=Integer.toString(cmin);//hhmm形式の時刻記録
scc.setAttribute("time",pptime);
そこで、キャッシュデータを使う方法を考えてみた。
public void doGet(..................
Calendar calendar = Calendar.getInstance();
int hour = calendar.get(Calendar.HOUR_OF_DAY);
int minute = calendar.get(Calendar.MINUTE);
int cmin=hour*60+minute;//現在時刻 整数値
ServletContext sc = getServletContext();
String ptime = (String)sc.getAttribute("time");//前回のキャッシュ時の時刻
String Cachex=(String)sc.getAttribute("cache");
if(cmin>=Integer.parseInt(ptime)&&cmin<=5+Integer.parseInt(ptime) && Cachex!=null){
//前回のキャッシュ作成から5分以上経過してないときは、キャッシュ利用
out.print(Cachex);
return;
}
Cache=ここで、poiの機能を使って読み取った 表示させたいデータ をセット
..............................................
ServletContext scc = getServletContext();
scc.setAttribute("cache", Cache);
String pptime="";
pptime=Integer.toString(cmin);//hhmm形式の時刻記録
scc.setAttribute("time",pptime);
2015年8月2日日曜日
グループウエアのアクセス集中緩和策
アクセス集中時の対策として、WEBサーバーとDBサーバー、どちらも分散化する方向で考えてみた。ゆくゆくはロードバランサーということなんだろうが、はたして、中古のPCでそれは可能か微妙である。
とりあえず、グループウエアのデータベースの書き込みと添付ファイルのアップーロードはマスターのサーバに送り、分散したサーバには、読み取り専用のスレーブDB、添付ファイルを置くことにした。Mysqlのレプリケーション、ファイルに対するrsyncで対処しようと考えている。うまくいけばいいのだが。
そういえば、アマゾンなども、情報をアップしても反映されるまで、時間がかかる。世界規模で、閲覧されるわけだから、多少の時間差もないとレプリケーションのようなこともむずかしいだろう。今回の件で、そのへんの事情がよくわかる気がする。
とりあえず、グループウエアのデータベースの書き込みと添付ファイルのアップーロードはマスターのサーバに送り、分散したサーバには、読み取り専用のスレーブDB、添付ファイルを置くことにした。Mysqlのレプリケーション、ファイルに対するrsyncで対処しようと考えている。うまくいけばいいのだが。
そういえば、アマゾンなども、情報をアップしても反映されるまで、時間がかかる。世界規模で、閲覧されるわけだから、多少の時間差もないとレプリケーションのようなこともむずかしいだろう。今回の件で、そのへんの事情がよくわかる気がする。
2015年8月1日土曜日
rsyncを使ってみた
rsyncで、特定のファイルを、更新したときだけ、コピーすることを考えてみた。-uでコピー元とコピー先を比較し、追加・更新されたファイル・ディレクトリのみをコピーします。
crontabで、5分間隔でチェックした場合
*/5 * * * * rsync -au --include="file.txt" --exclude="*" /mnt/windows/ /tenpu/
という具合でうまくいった。
リモートでもできるようだったが、面倒なので、共有を/mnt/windowsにマウントしている。
ポイントとして、コピー元の最後に/をつけるのを忘れないようにすること。(コピー先はつけてもつけなくてもいいらしい)
なかなか便利だが、いろいろ設定ができるため、使いこなすのもそれなりに知識がいる。
************
ちなみに、ディレクトリ内のすべてのファイルやその中のディレクトリ内も再帰的に指定したい場合は-rオプションをつかうようだが、-aオプションに含まれているらしい。-deleteはコピー元にない(削除された)ファイルをコピー先で削除します。コピー元とコピー先を同期します。-zで通信の圧縮が可能とか。
*/5 * * * * rsync -auz --delete /mnt/windows/ /tenpu/
といった具合にすれば5分間隔でフォルダ内のファイルの同期がとれる。
crontabで、5分間隔でチェックした場合
*/5 * * * * rsync -au --include="file.txt" --exclude="*" /mnt/windows/ /tenpu/
という具合でうまくいった。
リモートでもできるようだったが、面倒なので、共有を/mnt/windowsにマウントしている。
ポイントとして、コピー元の最後に/をつけるのを忘れないようにすること。(コピー先はつけてもつけなくてもいいらしい)
なかなか便利だが、いろいろ設定ができるため、使いこなすのもそれなりに知識がいる。
************
ちなみに、ディレクトリ内のすべてのファイルやその中のディレクトリ内も再帰的に指定したい場合は-rオプションをつかうようだが、-aオプションに含まれているらしい。-deleteはコピー元にない(削除された)ファイルをコピー先で削除します。コピー元とコピー先を同期します。-zで通信の圧縮が可能とか。
*/5 * * * * rsync -auz --delete /mnt/windows/ /tenpu/
といった具合にすれば5分間隔でフォルダ内のファイルの同期がとれる。
Mysql レプリケーション
Mysqlのレプリケーションの設定をやってみた。
以下のリンクを参考にさせてもらった。
http://dotnsf.blog.jp/archives/1028720878.html
1 マスターで
mysql > GRANT REPLICATION SLAVE ON *.* TO 'repl'@'192.168.1.0/255.255.255.0' IDENTIFIED BY 'password';
ネットワークアドレスの指定のため、192.168.1.0の最後は0とすることに注意
/etc/mysql/my.cnf
[mysqld]
log-bin=mysql-bin →もとのファイルではlog_binとなっていたが、log-binでいいようだ。
server-id=1001
として、service mysql restart
2 スレーブで
mysql > GRANT ALL PRIVILEGES ON *.* TO 'repl'@localhost IDENTIFIED BY 'password';
my.cnfの編集
[mysqld]
log-bin=mysql-bin
server-id=1002 として service mysql restart
3 マスターで
mysql > FLUSH TABLES WITH READ LOCK;
mysql > SHOW MASTER STATUS;
このとき、Fileのmysql-bin.00000?(6桁数字) Positionの3桁数字 をメモしておく
別のコンソールで
# mysqldump -u root -p mydb --lock-all-tables > mydbdump.db によりデータを保存
もとのコンソールで
mysql > UNLOCK TABLES;
4 データの移動
mydbdump.dbをスレーブに移動
5 スレーブで
# mysql -u repl -p mydb < mydbdump.db
mysql > CHANGE MASTER TO
MASTER_HOST='192.168.1.XXX',
MASTER_USER='repl',
MASTER_PASSWORD='password',
MASTER_LOG_FILE='mysql-bin.000031', ←3でメモした値
MASTER_LOG_POS=285; ←〃
mysql > START SLAVE;
※以上だが、実際にはうまくいかなかった。原因はいくつかあった。
・http://pyoonn.hatenablog.com/entry/2015/01/09/133102が参考になりました。どうやらコネクトしてないようだった。
# mysql -h 192.168.*.* -u repl で、接続確認しても、エラー
マスターで
grant all privileges on *.* to repl@"192.168.58.%" identified by 'password' with grant option;
で特権を与える。192.168.58.*のワイルドカードのホストのreplからアクセス可能に
スレーブで確認するには
mysql>SHOW SLAVE STATUS\G
このとき、Slave_IO_Running: Yesが表示されればOKだが、まだ、だめ
・さらに、iptablesがじゃましてないか確認したが、ディフォルトでOFFなってたので、関係なかった。
・そこで、
http://d.hatena.ne.jp/uriyuri/20081024/1224798772を参考にさせていただいた。
/etc/mysql/my.cnfの設定では
bind-address = 127.0.0.1
bind-address = (接続したいマシンのIPアドレス)
と、接続先を追加していくか、または、どのIPからも接続許可したいなら、いっそbind-addressをコメントアウトすればよいということらしい。
これで、なんとか、動くようになった。
※ひとつレプリケーションで注意が必要なことがあるようだ。
http://nippondanji.blogspot.jp/2009/03/mysql10.html にあるように
スレーブのデータは変更しないということ。
グループウエア等の設定では、十分注意が必要なところなようだ。
以下のリンクを参考にさせてもらった。
http://dotnsf.blog.jp/archives/1028720878.html
1 マスターで
mysql > GRANT REPLICATION SLAVE ON *.* TO 'repl'@'192.168.1.0/255.255.255.0' IDENTIFIED BY 'password';
ネットワークアドレスの指定のため、192.168.1.0の最後は0とすることに注意
/etc/mysql/my.cnf
[mysqld]
log-bin=mysql-bin →もとのファイルではlog_binとなっていたが、log-binでいいようだ。
server-id=1001
として、service mysql restart
2 スレーブで
mysql > GRANT ALL PRIVILEGES ON *.* TO 'repl'@localhost IDENTIFIED BY 'password';
my.cnfの編集
[mysqld]
log-bin=mysql-bin
server-id=1002 として service mysql restart
3 マスターで
mysql > FLUSH TABLES WITH READ LOCK;
mysql > SHOW MASTER STATUS;
このとき、Fileのmysql-bin.00000?(6桁数字) Positionの3桁数字 をメモしておく
別のコンソールで
# mysqldump -u root -p mydb --lock-all-tables > mydbdump.db によりデータを保存
もとのコンソールで
mysql > UNLOCK TABLES;
4 データの移動
mydbdump.dbをスレーブに移動
5 スレーブで
# mysql -u repl -p mydb < mydbdump.db
mysql > CHANGE MASTER TO
MASTER_HOST='192.168.1.XXX',
MASTER_USER='repl',
MASTER_PASSWORD='password',
MASTER_LOG_FILE='mysql-bin.000031', ←3でメモした値
MASTER_LOG_POS=285; ←〃
mysql > START SLAVE;
※以上だが、実際にはうまくいかなかった。原因はいくつかあった。
・http://pyoonn.hatenablog.com/entry/2015/01/09/133102が参考になりました。どうやらコネクトしてないようだった。
# mysql -h 192.168.*.* -u repl で、接続確認しても、エラー
マスターで
grant all privileges on *.* to repl@"192.168.58.%" identified by 'password' with grant option;
で特権を与える。192.168.58.*のワイルドカードのホストのreplからアクセス可能に
スレーブで確認するには
mysql>SHOW SLAVE STATUS\G
このとき、Slave_IO_Running: Yesが表示されればOKだが、まだ、だめ
・さらに、iptablesがじゃましてないか確認したが、ディフォルトでOFFなってたので、関係なかった。
・そこで、
http://d.hatena.ne.jp/uriyuri/20081024/1224798772を参考にさせていただいた。
/etc/mysql/my.cnfの設定では
bind-address = 127.0.0.1
bind-address = (接続したいマシンのIPアドレス)
と、接続先を追加していくか、または、どのIPからも接続許可したいなら、いっそbind-addressをコメントアウトすればよいということらしい。
これで、なんとか、動くようになった。
※ひとつレプリケーションで注意が必要なことがあるようだ。
http://nippondanji.blogspot.jp/2009/03/mysql10.html にあるように
スレーブのデータは変更しないということ。
グループウエア等の設定では、十分注意が必要なところなようだ。
VirtualBoxでUbuntu2台同時実行
VirtualBoxにホストオンリーアダプタを有効にして、2台のUbuntuを動かしてみた。実環境でテストもできないので、2台のMysqlサーバーのレプリケーション、Webアプリを試験的に動かすためです。
職場のグループウエアが、Mysqlがネックになってきて、混雑時に表示が遅くなってきたためだ。いまだに、メモリ1GB未満で、CPUも1Coreの一世代前のものなので、複数台で対処するしかないようだ。
とりあえず、グループウエアのほうは、DBの書き込みと読み込みを別のサーバに設定できるようにした。あとは、マスターのDBサーバとスレーブのDBサーバのレプリケーションがうまくいけばOKだ。
職場のグループウエアが、Mysqlがネックになってきて、混雑時に表示が遅くなってきたためだ。いまだに、メモリ1GB未満で、CPUも1Coreの一世代前のものなので、複数台で対処するしかないようだ。
とりあえず、グループウエアのほうは、DBの書き込みと読み込みを別のサーバに設定できるようにした。あとは、マスターのDBサーバとスレーブのDBサーバのレプリケーションがうまくいけばOKだ。
2015年7月30日木曜日
play2+scala
scalaはPlay frameworkでよく使われているらしい。Railsに似ている。
(javafxの利用も考えてみたが、どうもマイナーなようで、あまり情報が集められない。やはり主流はWEBサーバ用のようだ。)
試しにインストールしてみたが、なかなか一度でうまくはいかない。scalaの特徴を活かした便利なフレームワークではあるが、インストールの敷居はけっこう高いようだ。
いくつかひっかかったところをまとめてみた。
・最新版はplayでなくactivatorというコマンドを使用している。
・typesafe-activator-1.3.5-minimal版のほうでうまくいった。フルセット版(400MB以上ある)だと、すでにあるscalaと競合?したのかうまくいかなかった。
・activator.bat(win版の場合)のあるフォルダのPathを通して再起動。
・コマンドプロンプトで、上記フォルダに移動して、いろいろ操作。
activator newで、簡単にプロジェクタが作成できるようだ。activator uiとすると、WEB上で操作もできるという優れもの。
・eclipseで使えるようにするには、project/plugins.sbtというファイルを作成して、以下の記述をすると使えるようになります。
addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "2.4.0")
これが、なかなかわからなくて、苦労した。
このあと、activator eclipseというコマンドで処理したあと、eclipseを起動して「Existing Projects into Workspace」でワークスペースにインポートすることができる。
(javafxの利用も考えてみたが、どうもマイナーなようで、あまり情報が集められない。やはり主流はWEBサーバ用のようだ。)
試しにインストールしてみたが、なかなか一度でうまくはいかない。scalaの特徴を活かした便利なフレームワークではあるが、インストールの敷居はけっこう高いようだ。
いくつかひっかかったところをまとめてみた。
・最新版はplayでなくactivatorというコマンドを使用している。
・typesafe-activator-1.3.5-minimal版のほうでうまくいった。フルセット版(400MB以上ある)だと、すでにあるscalaと競合?したのかうまくいかなかった。
・activator.bat(win版の場合)のあるフォルダのPathを通して再起動。
・コマンドプロンプトで、上記フォルダに移動して、いろいろ操作。
activator newで、簡単にプロジェクタが作成できるようだ。activator uiとすると、WEB上で操作もできるという優れもの。
・eclipseで使えるようにするには、project/plugins.sbtというファイルを作成して、以下の記述をすると使えるようになります。
addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "2.4.0")
これが、なかなかわからなくて、苦労した。
このあと、activator eclipseというコマンドで処理したあと、eclipseを起動して「Existing Projects into Workspace」でワークスペースにインポートすることができる。
2015年7月28日火曜日
Scalaで学ぶ関数脳入門 パーサー2
P333 リスト8の確認
def test(caption:String,data:Stirng){
println(Caption+data)
read (new SimpleLexer(data))
}
def read(lexer:Simplelexer):Unit=lexer.nextToken match= {
case Token(lexer.EOF,value)=>println()
case token:Token=>print(token);read(lexer)
}
case token:Token=>print(token);read(lexer)のところで、再帰を使っている。lexerの中身は、readで処理されるたびに、先頭文字が1文字ずつ削除されていく。print(token)により、token.toStirngがプリントされるということのようだ。
P335 リスト9について
def expression = {
number
nextToken match {
case Token(...
....
ここでは、再帰は見当たらない?一桁数字+一桁数字の単純な式だけの処理をしているということだろうか?
このへんになってくると、パーサーの複雑さを感じる。
*********
いちおう、最後まで全ページを読んでみた。全体的に、関数型に関する記述は少ないので、関数型プログラミングの学習にはあまりならなかったが、基本的な並列処理やパーサの記述がとても参考になった。
def test(caption:String,data:Stirng){
println(Caption+data)
read (new SimpleLexer(data))
}
def read(lexer:Simplelexer):Unit=lexer.nextToken match= {
case Token(lexer.EOF,value)=>println()
case token:Token=>print(token);read(lexer)
}
case token:Token=>print(token);read(lexer)のところで、再帰を使っている。lexerの中身は、readで処理されるたびに、先頭文字が1文字ずつ削除されていく。print(token)により、token.toStirngがプリントされるということのようだ。
P335 リスト9について
def expression = {
number
nextToken match {
case Token(...
....
ここでは、再帰は見当たらない?一桁数字+一桁数字の単純な式だけの処理をしているということだろうか?
このへんになってくると、パーサーの複雑さを感じる。
*********
いちおう、最後まで全ページを読んでみた。全体的に、関数型に関する記述は少ないので、関数型プログラミングの学習にはあまりならなかったが、基本的な並列処理やパーサの記述がとても参考になった。
Scalaで学ぶ関数脳入門 パーサー
P332 リスト7 一から実装した簡単な字句解析器の例が出ていた。説明が簡潔なため、よく考えないとわからなかった。
case class Token(val tokenType:String,val value:String){
override der toString ="["+tokenType+":" "+value+"]"
}
class simpleLexer(input:Stirng){
val OPERATOR="OPERATOR"
val NUMBER="NUMBER"
val EOF="EOF"
var reader =new CarSequenceReader(input)
def netxToken():Token=|
while(!readre.atEnd){
reader.first match {
case c:Char if (c=='+' || c=='-")
=> return new Token(OPERATOR,takeFirst)
case ....................
case c:Char if (c==' ' || c== '\t'...) =>dump
..................
}
.......................
def takeFirst()={
val first =reader.first
reader=reader.drop(1)
first.toString
}
これは、先頭の文字を返すが、その先頭の文字を文字シーケンス(reader)から削除するらしい。
ただ、よくわからないのは、これがdumpの中で使われていて、dumpの返り値はUnitであること。dumpはStringを返すこともあるんだけど、:Unitとすれば、Stringは無視されるんということか?nextTokenの通常文字をみつけたときは、 Token(OPERATOR,takeFirst)というように、takeFirstの返り値Stringを使っているようだが。
def dump():Unit=reader.first match {
case c:Char if (c==' ' || c== '\t' || c=='\r' || c=='\n')
=> takeFirst ;dump
case _ =>
}
これは、空白を削除する。最初の文字が、空白、タブ、改行等なら、その最初の文字をtakeして、dumpの再帰で、空白等を削除するかチェック(空白等が連続してる場合もあるから)していく。空白等がなくなれば、何もせず、もとにもどるということのようだ。
case class Token(val tokenType:String,val value:String){
override der toString ="["+tokenType+":" "+value+"]"
}
class simpleLexer(input:Stirng){
val OPERATOR="OPERATOR"
val NUMBER="NUMBER"
val EOF="EOF"
var reader =new CarSequenceReader(input)
def netxToken():Token=|
while(!readre.atEnd){
reader.first match {
case c:Char if (c=='+' || c=='-")
=> return new Token(OPERATOR,takeFirst)
case ....................
case c:Char if (c==' ' || c== '\t'...) =>dump
..................
}
.......................
def takeFirst()={
val first =reader.first
reader=reader.drop(1)
first.toString
}
これは、先頭の文字を返すが、その先頭の文字を文字シーケンス(reader)から削除するらしい。
ただ、よくわからないのは、これがdumpの中で使われていて、dumpの返り値はUnitであること。dumpはStringを返すこともあるんだけど、:Unitとすれば、Stringは無視されるんということか?nextTokenの通常文字をみつけたときは、 Token(OPERATOR,takeFirst)というように、takeFirstの返り値Stringを使っているようだが。
def dump():Unit=reader.first match {
case c:Char if (c==' ' || c== '\t' || c=='\r' || c=='\n')
=> takeFirst ;dump
case _ =>
}
これは、空白を削除する。最初の文字が、空白、タブ、改行等なら、その最初の文字をtakeして、dumpの再帰で、空白等を削除するかチェック(空白等が連続してる場合もあるから)していく。空白等がなくなれば、何もせず、もとにもどるということのようだ。
2015年7月26日日曜日
Scalaで学ぶ関数脳入門 Scalaのメールボックス
P280 MailBoxは内部にMessage QueueおよびReceiver Queueを持っていて、send およびreceiveメソッドでメッセージの送受信を行う ことについて説明しているが、けっこうややこしい。
Message Queueとは、send側がメッセージを待機させておくところで、Receiver Queueは、receive側が待ち受け内容を待機させておくところのように見える。両者の準備がととのっていれば、ふたつのqueueの間で、データの受け渡しが行われるというふうに理解したが、、、。
Message Queueとは、send側がメッセージを待機させておくところで、Receiver Queueは、receive側が待ち受け内容を待機させておくところのように見える。両者の準備がととのっていれば、ふたつのqueueの間で、データの受け渡しが行われるというふうに理解したが、、、。
2015年7月20日月曜日
Scalaで学ぶ関数脳入門 変位
P202で、共変、反変の説明をしている。これまでscalaの本やネットの情報を見ても、わかりずらいところだ。
EのサブクラスがEsub、スーパークラスをEsuperとして説明している。
「変数funcは、引数としてEを受け取ることを要求している。一方で、Eは、Esuperの派生型なので、Esuperとしてふるまうことは保証されています。(中略)一方で、EはEsubがどのようにEを拡張しているか知らないため、Esubとしてふるまうことができない。そのため、funcはEsub型を受け取ることができない。」
おもしろい説明の例がありました。こちらです。以下のその抜粋です。参考にさせていただきました。
猫を何かに変換する装置の一種として、動物を変換する装置が含まれるのは自然です。動物を変換する装置で猫を変換できるからです。
また、何かを動物に変換する装置の一種として、何かを人間に変換する装置が含まれるのは自然です。人間も動物の一種だからです。
集合式で書くと
動物 ⊇ 猫 → 動物を何かに変換する装置 ⊆ 猫を何かに変換する装置 (反変性)
人間 ⊆ 動物 → 何かを人間に変換する装置 ⊆ 何かを動物に変換する装置 (共変性)
・動物を何かに変換するのは、猫を変換する装置、犬を変換する装置、、等の共通(AND)集合なので、当然、猫を変換する装置よりも集合としては小さくなるということでしょうか。?
・あるものを人間に変換する装置、あるものを犬に変換する装置、、、等の和(OR)集合が、あるものを動物に変換する装置、、と考えれば、集合の包含関係は上記のようになる?
Wikipediaには、以下の説明がある
T 型の引数を持つ関数呼び出し (fun f (x : T) : Integer と定義) は、T ≤ S のとき、fun g(x: S) : Integer と定義される関数 g で置換可能である。言い換えると、g は、引数の型に関して f より寛容であり、f と同様に Integer を返すので、f をいつでも置換できる。このように、関数引数を許す言語においては、 g ≤ f と f の引数の型とは反変である。
EのサブクラスがEsub、スーパークラスをEsuperとして説明している。
「変数funcは、引数としてEを受け取ることを要求している。一方で、Eは、Esuperの派生型なので、Esuperとしてふるまうことは保証されています。(中略)一方で、EはEsubがどのようにEを拡張しているか知らないため、Esubとしてふるまうことができない。そのため、funcはEsub型を受け取ることができない。」
おもしろい説明の例がありました。こちらです。以下のその抜粋です。参考にさせていただきました。
猫を何かに変換する装置の一種として、動物を変換する装置が含まれるのは自然です。動物を変換する装置で猫を変換できるからです。
また、何かを動物に変換する装置の一種として、何かを人間に変換する装置が含まれるのは自然です。人間も動物の一種だからです。
集合式で書くと
動物 ⊇ 猫 → 動物を何かに変換する装置 ⊆ 猫を何かに変換する装置 (反変性)
人間 ⊆ 動物 → 何かを人間に変換する装置 ⊆ 何かを動物に変換する装置 (共変性)
・動物を何かに変換するのは、猫を変換する装置、犬を変換する装置、、等の共通(AND)集合なので、当然、猫を変換する装置よりも集合としては小さくなるということでしょうか。?
・あるものを人間に変換する装置、あるものを犬に変換する装置、、、等の和(OR)集合が、あるものを動物に変換する装置、、と考えれば、集合の包含関係は上記のようになる?
Wikipediaには、以下の説明がある
T 型の引数を持つ関数呼び出し (fun f (x : T) : Integer と定義) は、T ≤ S のとき、fun g(x: S) : Integer と定義される関数 g で置換可能である。言い換えると、g は、引数の型に関して f より寛容であり、f と同様に Integer を返すので、f をいつでも置換できる。このように、関数引数を許す言語においては、 g ≤ f と f の引数の型とは反変である。
Scalaで学ぶ関数脳入門 抽出子
P183 パターンマッチングと抽出子
class FruitShop {
def niceSale(day:Day){
day match {
case Mysale(salePrice) => printf("Price: %s\n",salePrice)
}
}
}
......
object SaleValidator {
def unapply(day:Day):Boolean~={
day match {
case friday:Friday => true
case monday:Monday => true
case _ => false
}
}
}
object Mysale {
def unapply(day:Day):Option[(Double)]={
day match {
case SaleValidator() => Some(day.salePrice)
case _ => Some(day.price)
}
}
}
抽出子について...apply(ファクトリメソッド)の逆のことを行う。unapplyにより、インスタンスのdayの中の値を取り出すはたらきをする。
val Day(price)=dayで dayからpriceが抽出できる。
SaleValidatorのほうのunapplyはBooleanを返しています。applyが不要な抽出子オブジェクトということで、コップ本の26章の抽出子についての説明にあるようです。
パターンマッチで使うときには、戻り値はOptionかBooleanということらしい。こちらも参照させていただいた。この知識がないと、ここは理解しずらいところかも。。。
class FruitShop {
def niceSale(day:Day){
day match {
case Mysale(salePrice) => printf("Price: %s\n",salePrice)
}
}
}
......
object SaleValidator {
def unapply(day:Day):Boolean~={
day match {
case friday:Friday => true
case monday:Monday => true
case _ => false
}
}
}
object Mysale {
def unapply(day:Day):Option[(Double)]={
day match {
case SaleValidator() => Some(day.salePrice)
case _ => Some(day.price)
}
}
}
抽出子について...apply(ファクトリメソッド)の逆のことを行う。unapplyにより、インスタンスのdayの中の値を取り出すはたらきをする。
val Day(price)=dayで dayからpriceが抽出できる。
SaleValidatorのほうのunapplyはBooleanを返しています。applyが不要な抽出子オブジェクトということで、コップ本の26章の抽出子についての説明にあるようです。
パターンマッチで使うときには、戻り値はOptionかBooleanということらしい。こちらも参照させていただいた。この知識がないと、ここは理解しずらいところかも。。。
Scalaで学ぶ関数脳入門
Scalaで学ぶ関数脳入門を読んでみた。この本も、翻訳本でないので、プログラムの例が理解しやすい。抽象的な内容を理解するには、具体的な例をいろいろ知る必要があるということを、あらためて知らされる。
P180で暗黙の型変換とcaseクラスを組み合わせた、パターンマッチングの紹介があった。
case class Apple(price:Int,num:Int)
case class TotalCalc(price:Int,num:Int){ ①
def totalPrice = price * num
}
implicit def conv(apple:Apple)=TotalCalc(apple.price,apple.num) ②
apple=Apple(100,3)
apple totalPriceで求められる
apple totalPriceのappleは暗黙の型変換でTotalCalcに変換され、その上で、①のtotalPriceを呼び出していることになる。 擬似的に、appleの型をTotalCalcの型に変換し、totalPriceがあたかもappleに定義されているかのように呼び出せる。(ref:scala逆引きレシピ300 P38)
P180で暗黙の型変換とcaseクラスを組み合わせた、パターンマッチングの紹介があった。
case class Apple(price:Int,num:Int)
case class TotalCalc(price:Int,num:Int){ ①
def totalPrice = price * num
}
implicit def conv(apple:Apple)=TotalCalc(apple.price,apple.num) ②
apple=Apple(100,3)
apple totalPriceで求められる
apple totalPriceのappleは暗黙の型変換でTotalCalcに変換され、その上で、①のtotalPriceを呼び出していることになる。 擬似的に、appleの型をTotalCalcの型に変換し、totalPriceがあたかもappleに定義されているかのように呼び出せる。(ref:scala逆引きレシピ300 P38)
2015年7月15日水曜日
scalaファンクショナルデザイン P243
def sum(x: List[Int]):Int={
my.Util.trace("sum",x) {
if(x.tail=-Nil) x.head
else x.head +sum(x.tail)
}
}
..
var level =0
var indicator="_ "
def trace[T](fname:String,arg:Any*)(body:=>T): T= {
println((indicator*lever)+fname+" ("+arg.mkString(",")+")")
level += 1
var ret =body
level -+1
println((indicator*level)+fname+"_ "+ret)
ret
}
...
とあり、最初、(body:=>T)の意味が分からなかったが、要するに、
{ if(x.tail=-Nil) x.head
else x.head +sum(x.tail)
}
の部分に対応するということのようだ。ここで、今の場合はIntの値が計算される。
2015年7月12日日曜日
scalaファンクショナルデザイン P118
クロージャーの利点について書かれてあります。
○コード削減重視バージョン
...............
def output(sw:Int)={
val sum=....
.......
for (.............
for (k<-0 to3){
.......................※計算あり....
if (sw==1) .......
else .................
println(output(1))
println(output(2))........
これだと、その都度、※の部分で同じ計算がされてしまう
○クロージャーバージョン
def output() ={
val sum= ......
.........
for(...........
for (k<-0 to3){
.......................※計算あり....
}
(sw:Int)=> { //クロージャー生成
....
for (k<-0 to 3) {.............
if (sw==1) .......
else .................
val f=opuput()
println(f(1))
println(f(2))
................
※の部分がクロージャーの外側にあるので、最初の1回しか実行されない。
ということのようだ。
いろいろなサイトでも、クロージャーについてわかりやすく書かれているので参考になりました。javascriptやjqueryでも利用されているのだと、今頃になって知りました。
○コード削減重視バージョン
...............
def output(sw:Int)={
val sum=....
.......
for (.............
for (k<-0 to3){
.......................※計算あり....
if (sw==1) .......
else .................
println(output(1))
println(output(2))........
これだと、その都度、※の部分で同じ計算がされてしまう
○クロージャーバージョン
def output() ={
val sum= ......
.........
for(...........
for (k<-0 to3){
.......................※計算あり....
}
(sw:Int)=> { //クロージャー生成
....
for (k<-0 to 3) {.............
if (sw==1) .......
else .................
val f=opuput()
println(f(1))
println(f(2))
................
※の部分がクロージャーの外側にあるので、最初の1回しか実行されない。
ということのようだ。
いろいろなサイトでも、クロージャーについてわかりやすく書かれているので参考になりました。javascriptやjqueryでも利用されているのだと、今頃になって知りました。
2015年7月11日土曜日
Webカメラの活用:離れた場所の様子を見る
狭い場所で行われる内容を、大勢の人が見たいという必要があるとき、別の広い部屋まで映像を配信したいことがあります。それぞれの場所にネットワーク配線がすでにしてあるところであれば、すぐできますが、そうでない場合はなかなか面倒です。
簡単に、なるべくお金をかけずにできないかということで、考えてみました。ビデオカメラからつなぐには、RCAケーブルは30から50mぐらいが限界のようですが、LANケーブルなら100mまでOkです。
Webカメラ、クロスLanケーブル、パソコン2台にフリーソフトでなんとかできるようです。余っていた長いLANケーブルがあったので、クロスでコネクタをつけてみました。
・送信側PCにつなげるWebカメラは、なんでもかまわない。
・パソコンに表示するために、USBCamDispというフリーソフトを送信側のPCで使用する。
・送信側のPCの音声は、録音デバイスのところで、Webカメラ内蔵のマイクの音声をモニター(聴く)できる設定にする。ハウリングしないように、スピーカの音量の調整は必要。
・ネットワークの設定は、2台のPCのIPアドレスを固定にする。ゲートウエイやDNSは、任意でかまわないようです。IPアドレスは、送信側192.168.1.1と受信側192.168.1.2のようにする。
・brynhildrというリモートデスクトップソフトを2台のPCの適当なところに保存しておく。一部、アセンブラ?も使用しているらしく高速です。
最初、送信側をserverモードにして、Ipアドレス192.168.1.1にして、パスワードを設定。ファイヤーウオールは、パブリックネットワークで許可なるようにします。ここに気づかず、最初、苦労しました。セキュリティが心配で、プライベートネットワークで許可としたところだめだったのです。
受信側ではClientモードで192.168.1.1アクセスすれば、うまくつながります。
・受信側PCに大画面液晶TVなり、液晶プロジェクタなりを接続すれば、完成です。
簡単に、なるべくお金をかけずにできないかということで、考えてみました。ビデオカメラからつなぐには、RCAケーブルは30から50mぐらいが限界のようですが、LANケーブルなら100mまでOkです。
Webカメラ、クロスLanケーブル、パソコン2台にフリーソフトでなんとかできるようです。余っていた長いLANケーブルがあったので、クロスでコネクタをつけてみました。
・送信側PCにつなげるWebカメラは、なんでもかまわない。
・パソコンに表示するために、USBCamDispというフリーソフトを送信側のPCで使用する。
・送信側のPCの音声は、録音デバイスのところで、Webカメラ内蔵のマイクの音声をモニター(聴く)できる設定にする。ハウリングしないように、スピーカの音量の調整は必要。
・ネットワークの設定は、2台のPCのIPアドレスを固定にする。ゲートウエイやDNSは、任意でかまわないようです。IPアドレスは、送信側192.168.1.1と受信側192.168.1.2のようにする。
・brynhildrというリモートデスクトップソフトを2台のPCの適当なところに保存しておく。一部、アセンブラ?も使用しているらしく高速です。
最初、送信側をserverモードにして、Ipアドレス192.168.1.1にして、パスワードを設定。ファイヤーウオールは、パブリックネットワークで許可なるようにします。ここに気づかず、最初、苦労しました。セキュリティが心配で、プライベートネットワークで許可としたところだめだったのです。
受信側ではClientモードで192.168.1.1アクセスすれば、うまくつながります。
・受信側PCに大画面液晶TVなり、液晶プロジェクタなりを接続すれば、完成です。
2015年7月9日木曜日
Scalaファンクショナルデザイン P45
Scalaファンクショナルデザインという本が出たので、読み始めてみた。簡潔で読みやすい。
これまで、他のScalaの本で読んで来たことを、振り返って、あいまいだった知識の整理に役立つ。
2行目から
関数オブジェクトは、Function1トレイトやFunction2トレイトをインスタンス化して作られたオブジェクトです。
7行目から
~関数オブジェクトは、変数に格納できるなど、値としての性質を持つことから、クラスでもメソッドでもなく、オブジェクトの一種と考えるのが妥当でしょう。
とある。最初、意味が分かりにくかったが、何回か読み直して、なんとなく理解?した。
関数オブジェクトは、「関数のはたらき」そのものであり、そのはたらきそのものを、変数に格納できるということであり、またそのはたらきを、値とみなすということ。値とみなせるんだから、どちらかといえば、オブジェクト(インスタンス化したもの)だろう。。ということだろうか。
したから7行目より
FuncitonXトレイトにはapplyという抽象メソッドが宣言されており、apply本体が関数本体そのものになります。まず、 関数リテラルが評価されると、FunctionXによるオブジェクトがつくられ、そのときに関数リテラルの「=>」記号の右側がapplyの処理内容として実装されます。以後、関数呼び出しをするとapplyの内容が実行されます。
fun(123)はfun.apply(123)と等価とすることで、fun(123)のように関数呼び出しの形に見えるようにしているということ?と理解したが、いいんだろうか。
P40でapplyの存在理由についてふれている。
fun.apply(123)の例で、ここには関数というものがない。そして、メソッドがないと処理手続きができない。
funは、関数オブジェクトが格納された変数。 実際にはfun関数を呼び出すというのは、格納されているオブジェクトのapplyメソッドを呼び出すことにあたる。
2015年6月30日火曜日
scala関数型デザイン&プログラミング P243
モノイド、モナドの章は、抽象的な内容で難しいといえば難しいのだが、試行錯誤の文章が少ないので、パートⅡの章に比べれば読みやすい。途中の問題への取り組みはあちこち省き、読み進んだ。
結合律の説明がすぐには理解できなかったので、丁寧にたどってみた。
x.flatMap(f).flatMap(g)==x.flatMap(a=>f(a).flatMap(g))の結合律で、xをSome(v)に置き換えると
Some(v).flatMap(f).flatMap(g) == Some(v).flatMap(a=>f(a).flatMap(g))であることを示す。
def flatMap[B](f:A=>Option[B]):Option[B]だから、
左辺のSome(v).flatMap(f)の部分はSome(v)のvに関数fを適用してf(v):Option[B]となる。
右辺のほうは、Some(v)のvに関数a=>f(a).flatMap(g)を適用するので、
v=>f(v).flatMap(g)で、結局f(v).flatMap(g)
Exercise11.7 クライスリ関数composeを実装せよ
def compose[A,B,C](f: A => F[B], g: B => F[C]): A => F[C] =
a => flatMap(f(a))(g)
f: A => F[B]の部分は、a=>f(a)で、次にg: B => F[C]のところは、flatMapを使うしかない。
( def flatMap(g:B=>F[C]):F[C]とみなして )
f(a).flatMap(g)とも書けるが、flatMap(f(a))(g)ということ。
Exercise 11.9 flatMapの観点からの結合律と、composeの観点からの結合律の式が等価であることを証明せよ。
compose(compose(f, g), h) == compose(f, compose(g, h))
a => flatMap(compose(f, g)(a))(h) == a => flatMap(f(a))(compose(g, h))
a => flatMap((b => flatMap(f(b))(g))(a))(h) == a => flatMap(f(a))(b => flatMap(g(b))(h))
左辺を少し簡単にすると
( b => flatMap(f(b))(g) )(a)は b => flatMap(f(b))(g)にaを適用するということ
だから a=> flatMap(f(a))(g) つまり下記のようになる
a => flatMap(flatMap(f(a))(g))(h) == a => flatMap(f(a))(b => flatMap(g(b))(h))
aを除いて簡単にする。f(a)の代わりにxとすると
flatMap(flatMap(x)(g))(h) == flatMap(x)(b => flatMap(g(b))(h))
文字を置き換えると
flatMap(flatMap(x)(f))(g) == flatMap(x)(a => flatMap(f(a))(g))
ん~ けっこう、ややこしい。
結合律の説明がすぐには理解できなかったので、丁寧にたどってみた。
x.flatMap(f).flatMap(g)==x.flatMap(a=>f(a).flatMap(g))の結合律で、xをSome(v)に置き換えると
Some(v).flatMap(f).flatMap(g) == Some(v).flatMap(a=>f(a).flatMap(g))であることを示す。
def flatMap[B](f:A=>Option[B]):Option[B]だから、
左辺のSome(v).flatMap(f)の部分はSome(v)のvに関数fを適用してf(v):Option[B]となる。
右辺のほうは、Some(v)のvに関数a=>f(a).flatMap(g)を適用するので、
v=>f(v).flatMap(g)で、結局f(v).flatMap(g)
Exercise11.7 クライスリ関数composeを実装せよ
def compose[A,B,C](f: A => F[B], g: B => F[C]): A => F[C] =
a => flatMap(f(a))(g)
f: A => F[B]の部分は、a=>f(a)で、次にg: B => F[C]のところは、flatMapを使うしかない。
( def flatMap(g:B=>F[C]):F[C]とみなして )
f(a).flatMap(g)とも書けるが、flatMap(f(a))(g)ということ。
Exercise 11.9 flatMapの観点からの結合律と、composeの観点からの結合律の式が等価であることを証明せよ。
compose(compose(f, g), h) == compose(f, compose(g, h))
a => flatMap(compose(f, g)(a))(h) == a => flatMap(f(a))(compose(g, h))
a => flatMap((b => flatMap(f(b))(g))(a))(h) == a => flatMap(f(a))(b => flatMap(g(b))(h))
左辺を少し簡単にすると
( b => flatMap(f(b))(g) )(a)は b => flatMap(f(b))(g)にaを適用するということ
だから a=> flatMap(f(a))(g) つまり下記のようになる
a => flatMap(flatMap(f(a))(g))(h) == a => flatMap(f(a))(b => flatMap(g(b))(h))
aを除いて簡単にする。f(a)の代わりにxとすると
flatMap(flatMap(x)(g))(h) == flatMap(x)(b => flatMap(g(b))(h))
文字を置き換えると
flatMap(flatMap(x)(f))(g) == flatMap(x)(a => flatMap(f(a))(g))
ん~ けっこう、ややこしい。
2015年6月27日土曜日
scala関数型デザイン&プログラミング P195
Exercise 9.7 flatMapをベースとしてproductとmap2を実装せよ
def product[A,B](p: Parser[A], p2: => Parser[B]): Parser[(A,B)] =
flatMap(p)(a => map(p2)(b => (a,b)))
def map2[A,B,C](p: Parser[A], p2: => Parser[B])(f: (A,B) => C): Parser[C] =
for { a <- p; b <- p2 } yield f(a,b)
for内包表記は、もう忘れていた
P74を参考にすれば
p flatMap ( a =>
p2 map ( b =>
f(a,b))) という意味になる
Exercise 9.8 mapをflatMapや他のコンビネータをベースにして表現せよ
def map[A,B](p: Parser[A])(f: A => B): Parser[B] =
p.flatMap(a => succeed(f(a)))
def product[A,B](p: Parser[A], p2: => Parser[B]): Parser[(A,B)] =
flatMap(p)(a => map(p2)(b => (a,b)))
def map2[A,B,C](p: Parser[A], p2: => Parser[B])(f: (A,B) => C): Parser[C] =
for { a <- p; b <- p2 } yield f(a,b)
for内包表記は、もう忘れていた
P74を参考にすれば
p flatMap ( a =>
p2 map ( b =>
f(a,b))) という意味になる
Exercise 9.8 mapをflatMapや他のコンビネータをベースにして表現せよ
def map[A,B](p: Parser[A])(f: A => B): Parser[B] =
p.flatMap(a => succeed(f(a)))
scala関数型デザイン&プログラミング P192-
●Exercise9.1 productを使ってコンビネータmap2を実装し、これを使って、manyをベースとしてmany1を実装せよ。
def map2[A,B,C](p: Parser[A], p2: Parser[B])( f: (A,B) => C): Parser[C] =
map(product(p, p2))(f.tupled)
tupledは、2引数関数fをタプルを引数とする関数に変換する。productの返値がParser[(A,B)]で中身がタプルだから、mapが適用できるということらしい。
def many1[A](p: Parser[A]): Parser[List[A]] =
map2(p, many(p))(_ :: _)
●Exercise9.2 productの振る舞いを定義する法則を考え出せ
解答を訳してみたが、内容は難しい。
`product` は結合則をみたす。次の2つの式は等しい:
(a ** b) ** c
a ** (b ** c)
違うのは、ペアの入れ子の状態である。 `(a ** b) ** c` パーサーは `((A,B), C)`をかえす。( `a ** (b ** c)` がn `(A, (B,C))`をかえすのと違い)
.入れ子のタプルをフラットな3タプルに変換する関数 `unbiasL` と `unbiasR` を定義できる。
def unbiasL[A,B,C](p: ((A,B), C)): (A,B,C) = (p._1._1, p._1._2, p._2)
def unbiasR[A,B,C](p: (A, (B,C))): (A,B,C) = (p._1, p._2._1, p._2._2)
これらの関数により、結合則がいえる。
(a ** b) ** c map (unbiasL) == a ** (b ** c) map (unbiasR)
2つの関係の間に、自明な全単射がある場合に、~=を使うことがある。
(a ** b) ** c ~= a ** (b ** c)
`map` や `product`も興味深いリレーションシップをもつ。 2つのパーサーのプロダクトを実行の前でも後でもMapが可能である。(そのふるまいに影響与えることなく)
a.map(f) ** b.map(g) == (a ** b) map { case (a,b) => (f(a), g(b)) }
たとえば,もし`a` と `b` が両方とも `Parser[String]`で `f` と `g` のどちらも文字の長さを計算されたものだとするなら、 aの結果をその長さにmapしても、あるいは、プロダクトの後にやっても、どちらでも問題ない。12章でこの法則をもう少し検討する
●Exercise9.3 先へ進む前にor、map2、succeedをベースとしてmanyを定義できるか検討せよ
def many[A](p: Parser[A]): Parser[List[A]] =
map2(p, many(p))(_ :: _) or succeed(List())
manyを再帰的に使っている。失敗したら空のリストを返す
●Exercise9.4 map2とsucceedを使って先のlistOfNコンビネータを実装せよ
def listOfN[A](n: Int, p: Parser[A]): Parser[List[A]] =
if (n <= 0) succeed(List())
else map2(p, listOfN(n-1, p))(_ :: _)
●Exercise9.5 第7章で示したように、非正格性に別のコンビネータで対処することもできる。ここでもそれを試して、既存のコンビネータに必要な変更を追加せよ。このアプローチをここで試すことについてどう思うか。
`wrap`というコンビネータを紹介する
def wrap[A](p: => Parser[A]): Parser[A]
manyの定義は
def many[A](p: Parser[A]): Parser[List[A]] =
map2(p, wrap(many(p)))(_ :: _) or succeed(List())
英文の説明がいまいちよくわからない
In the parallelism chapter, we were particularly interested in avoiding having `Par` objects that took as much time and space to build as the corresponding serial computation, and the `delay` combinator let us control this more carefully. Here, this isn't as much of a concern, and having to think carefully each time we `map2` to decide whether we need to call `wrap` seems like unnecessary friction for users of the API.
def flatMap[A,B](p:Parser[A])(f:A=.Parser[B]):Parser[B]
●Exercise9.6 flatMapと他のコンビネータをつかって、文脈依存パーサーを記述せよ
implicit def regex(r:Regex):Parser[String]
for {
digit <- "[0-9]+".r
val n = digit.toInt
_ <- listOfN(n, char('a'))
} yield n
これも、flatMapで表せるのだろうが、いまいち勉強不足
温度変化グラフをVb.net2010で表示
以前は、PICを使って温度変化を表示していたが、最近はarduinoという便利な基板があるので、そちらを使ってみた。センサーはLM35。
http://projectsbiotope.blogspot.jp/2010/01/arduino_25.htmlにつなぎ方が出ている。
http://kana-soft.com/tech/sample_0008.htmでシリアル通信ソフトを用意して、グラフ表示
できるようにしてみました。
ソース付き実行ファイルはこちら
センサー部分は、空気中でないとうまく動作しないようです。液体等の温度変化見るには、エポキシ樹脂等で固める必要あるようです。
http://projectsbiotope.blogspot.jp/2010/01/arduino_25.htmlにつなぎ方が出ている。
http://kana-soft.com/tech/sample_0008.htmでシリアル通信ソフトを用意して、グラフ表示
できるようにしてみました。
ソース付き実行ファイルはこちら
センサー部分は、空気中でないとうまく動作しないようです。液体等の温度変化見るには、エポキシ樹脂等で固める必要あるようです。
2015年6月20日土曜日
scala関数型デザイン&プログラミング P170
Exercise8.13 空でないリストを生成するlistOf1を定義し、このジェネレータを利用するようにmaxの仕様を更新せよ
def listOf1[A](g: Gen[A]): SGen[List[A]] =
SGen(n => g.listOfN(n max 1))
最低値が0にならないようにしている?
val maxProp1 = forAll(listOf1(smallInt)) { l =>
val max = l.max
!l.exists(_ > max) // lの中にmaxより大きい値はないはず
}
Exercise8.14 List[Int]のソートなどに利用できるList.sortedの振る舞いを検証するためのプロパティを記述せよ。
val sortedProp = forAll(listOf(smallInt)) { ns =>
val nss = ns.sorted
// どのソート済みのリストも、空か、一つの要素かで、 aがbより大きいような連続(a,b)要素ではない。
(ns.isEmpty || nss.tail.isEmpty || !ns.zip(ns.tail).exists {
case (a,b) => a > b
})
// また、ソート済みリストは入力リストの要素をすべて持っている
&& !ns.exists(!nss.contains(_))
// また、入力リストにない要素はない。
&& !nss.exists(!ns.contains(_))
}
!ns.zip(ns.tail).exists { case (a,b) => a > b } これの意味は? List(1,2,3).zip(List(2,3)はList((1,2),(2,3))つまり、リストの中から連続した2つの要素のペアを取り出すことになる。そこに、逆順の要素があればTrue、!により、false
でも、nsは、ソート済みでないから、falseがあり得るのでないか? nsがnssなら分かるが
contains(x)はxが要素に含まれているかどうかを調べる.
!ns.exists(!nss.contains(_))は、!ns.exists(_=>!nss.contains(_))ということで、入力リストの各要素に対して、ソート済みリストに存在しないものがあるかチェックしている。もちろんないので、falseで!により、Trueになる。ということ?
この章のこの後ののExerciseは、難易度が高く、パス
def listOf1[A](g: Gen[A]): SGen[List[A]] =
SGen(n => g.listOfN(n max 1))
最低値が0にならないようにしている?
val maxProp1 = forAll(listOf1(smallInt)) { l =>
val max = l.max
!l.exists(_ > max) // lの中にmaxより大きい値はないはず
}
Exercise8.14 List[Int]のソートなどに利用できるList.sortedの振る舞いを検証するためのプロパティを記述せよ。
val sortedProp = forAll(listOf(smallInt)) { ns =>
val nss = ns.sorted
// どのソート済みのリストも、空か、一つの要素かで、 aがbより大きいような連続(a,b)要素ではない。
(ns.isEmpty || nss.tail.isEmpty || !ns.zip(ns.tail).exists {
case (a,b) => a > b
})
// また、ソート済みリストは入力リストの要素をすべて持っている
&& !ns.exists(!nss.contains(_))
// また、入力リストにない要素はない。
&& !nss.exists(!ns.contains(_))
}
!ns.zip(ns.tail).exists { case (a,b) => a > b } これの意味は? List(1,2,3).zip(List(2,3)はList((1,2),(2,3))つまり、リストの中から連続した2つの要素のペアを取り出すことになる。そこに、逆順の要素があればTrue、!により、false
でも、nsは、ソート済みでないから、falseがあり得るのでないか? nsがnssなら分かるが
contains(x)はxが要素に含まれているかどうかを調べる.
!ns.exists(!nss.contains(_))は、!ns.exists(_=>!nss.contains(_))ということで、入力リストの各要素に対して、ソート済みリストに存在しないものがあるかチェックしている。もちろんないので、falseで!により、Trueになる。ということ?
この章のこの後ののExerciseは、難易度が高く、パス
scala関数型デザイン&プログラミング P167
Exercise8.10 GenをSGenに変換するヘルパー関数を実装せよ。これはGenのメソッドとして追加できる。 unsized(すべてのサイズに合うという意味)
def unsized: SGen[A] = SGen(_ => this)
なぜ、Intの部分が_でいいのか?
Exercise8.11 当然のことながら、SGenは少なくともGenと同じ演算の多くをサポートし、その実装はかなり機械的である。Genの対応する関数にデリゲートするするだけの便利な関数をSGenで定義せよ。
case class Gen[+A](sample: State[RNG,A]) {
def map[B](f: A => B): Gen[B] =
Gen(sample.map(f))
def flatMap[B](f: A => Gen[B]): Gen[B] =
Gen(sample.flatMap(a => f(a).sample))
def **[B](g: Gen[B]): Gen[(A,B)] =
(this map2 g)((_,_))
}
が、すでにGenの中にあるとして?、のようだ。
case class SGen[+A](g: Int => Gen[A]) {
def apply(n: Int): Gen[A] = g(n)
def map[B](f: A => B): SGen[B] =
SGen(g andThen (_ map f))
def flatMap[B](f: A => Gen[B]): SGen[B] =
SGen(g andThen (_ flatMap f))
def **[B](s2: SGen[B]): SGen[(A,B)] =
SGen(n => apply(n) ** s2(n))
}
andThenは関数の合成 (_ map f)等は _ =>_ map f ということ?
Genの中では、**は、map2をつかって、AとBを結合して(A,B)にするということのようだ。
これを使って、SGenの中では、 apply(n)がGen[A]で、s2(n)がGen[B]となり、apply(n)**s2(n)が、Gen[(A,B)]となるということ?
Exercise8.12 明示的なサイズを受け取らないListOfコンビネータを実装せよ。この実装は、GenでなくSGenを返し、要求されたサイズのリストを生成する。
def listOf[A](g:Gen[A]):SGen[List[A]] =
SGen(n => g.listOfN(n))
SGenのイメージがいまいちつかめない
def unsized: SGen[A] = SGen(_ => this)
なぜ、Intの部分が_でいいのか?
Exercise8.11 当然のことながら、SGenは少なくともGenと同じ演算の多くをサポートし、その実装はかなり機械的である。Genの対応する関数にデリゲートするするだけの便利な関数をSGenで定義せよ。
case class Gen[+A](sample: State[RNG,A]) {
def map[B](f: A => B): Gen[B] =
Gen(sample.map(f))
def flatMap[B](f: A => Gen[B]): Gen[B] =
Gen(sample.flatMap(a => f(a).sample))
def **[B](g: Gen[B]): Gen[(A,B)] =
(this map2 g)((_,_))
}
が、すでにGenの中にあるとして?、のようだ。
case class SGen[+A](g: Int => Gen[A]) {
def apply(n: Int): Gen[A] = g(n)
def map[B](f: A => B): SGen[B] =
SGen(g andThen (_ map f))
def flatMap[B](f: A => Gen[B]): SGen[B] =
SGen(g andThen (_ flatMap f))
def **[B](s2: SGen[B]): SGen[(A,B)] =
SGen(n => apply(n) ** s2(n))
}
andThenは関数の合成 (_ map f)等は _ =>_ map f ということ?
Genの中では、**は、map2をつかって、AとBを結合して(A,B)にするということのようだ。
これを使って、SGenの中では、 apply(n)がGen[A]で、s2(n)がGen[B]となり、apply(n)**s2(n)が、Gen[(A,B)]となるということ?
Exercise8.12 明示的なサイズを受け取らないListOfコンビネータを実装せよ。この実装は、GenでなくSGenを返し、要求されたサイズのリストを生成する。
def listOf[A](g:Gen[A]):SGen[List[A]] =
SGen(n => g.listOfN(n))
SGenのイメージがいまいちつかめない
2015年6月18日木曜日
scala関数型デザイン&プログラミング P168
type MaxSize = Int
case class Prop(run: (MaxSize,TestCases,RNG) => Result)
def forAll[A](g: SGen[A])(f: A => Boolean): Prop =
forAll(g(_))(f)
def forAll[A](g: Int => Gen[A])(f: A => Boolean): Prop = Prop {
(max,n,rng) =>
val casesPerSize = (n - 1) / max + 1
val props: Stream[Prop] =
Stream.from(0).take((n min max) + 1).map(i => forAll(g(i))(f))
val prop: Prop =
props.map(p => Prop { (max, n, rng) =>
p.run(max, casesPerSize, rng)
}).toList.reduce(_ && _)
prop.run(max,n,rng)
}
n min maxはnとmaxの小さいほうを返す
Stream.from(0).take((n min max) + 1).map(i => forAll(g(i))(f))はnかmaxの小さいほうの数分のStream(中身はiをもとにしてつくったforAll(g(i))(f)):Propを生成する。これをpopsとしている。
props:Stream[Prop]からmapで props.map(p => Prop { (max, n, rng) =>p.run(max, casesPerSize, rng) })をつくる。これは、(max,n,rng)=>p.run(max, casesPerSize, rng) より最終的にp.run(max, casesPerSize, rng)に変換されるということか。
toList.reduce(_&&_)で、StreamをListにして、要素を&&でつなぐということのようだ。
こういったテストの経験もないこともあり、いまいちすっきり理解できない。
case class Prop(run: (MaxSize,TestCases,RNG) => Result)
def forAll[A](g: SGen[A])(f: A => Boolean): Prop =
forAll(g(_))(f)
def forAll[A](g: Int => Gen[A])(f: A => Boolean): Prop = Prop {
(max,n,rng) =>
val casesPerSize = (n - 1) / max + 1
val props: Stream[Prop] =
Stream.from(0).take((n min max) + 1).map(i => forAll(g(i))(f))
val prop: Prop =
props.map(p => Prop { (max, n, rng) =>
p.run(max, casesPerSize, rng)
}).toList.reduce(_ && _)
prop.run(max,n,rng)
}
n min maxはnとmaxの小さいほうを返す
Stream.from(0).take((n min max) + 1).map(i => forAll(g(i))(f))はnかmaxの小さいほうの数分のStream(中身はiをもとにしてつくったforAll(g(i))(f)):Propを生成する。これをpopsとしている。
props:Stream[Prop]からmapで props.map(p => Prop { (max, n, rng) =>p.run(max, casesPerSize, rng) })をつくる。これは、(max,n,rng)=>p.run(max, casesPerSize, rng) より最終的にp.run(max, casesPerSize, rng)に変換されるということか。
toList.reduce(_&&_)で、StreamをListにして、要素を&&でつなぐということのようだ。
こういったテストの経験もないこともあり、いまいちすっきり理解できない。
scala関数型デザイン&プログラミング p165
リスト8-3を少し確認してみた。
def randomStream[A](g: Gen[A])(rng: RNG): Stream[A] =
Stream.unfold(rng)(rng => Some(g.sample.run(rng)))
def forAll[A](as: Gen[A])(f: A => Boolean): Prop = Prop {
(n,rng) => randomStream(as)(rng).zip(Stream.from(0)).take(n).map {
case (a, i) => try {
if (f(a)) Passed else Falsified(a.toString, i)
} catch { case e: Exception => Falsified(buildMsg(a, e), i) }
}.find(_.isFalsified).getOrElse(Passed)
}
randomStream(as)(rng).zip(Stream.from(0)).take(n)の部分で、(a,i)のストリームをn個 生成
するようだ。
その後、PassedかFalsifiedにmapするということか。
.find(_.isFalsified).getOrElse(Passed)では、最初に失敗にぶつかるとそこでストップ?
def buildMsg[A](s: A, e: Exception): String =
s"test case: $s\n" +
s"generated an exception: ${e.getMessage}\n" +
s"stack trace:\n ${e.getStackTrace.mkString("\n")}"
def randomStream[A](g: Gen[A])(rng: RNG): Stream[A] =
Stream.unfold(rng)(rng => Some(g.sample.run(rng)))
def forAll[A](as: Gen[A])(f: A => Boolean): Prop = Prop {
(n,rng) => randomStream(as)(rng).zip(Stream.from(0)).take(n).map {
case (a, i) => try {
if (f(a)) Passed else Falsified(a.toString, i)
} catch { case e: Exception => Falsified(buildMsg(a, e), i) }
}.find(_.isFalsified).getOrElse(Passed)
}
randomStream(as)(rng).zip(Stream.from(0)).take(n)の部分で、(a,i)のストリームをn個 生成
するようだ。
その後、PassedかFalsifiedにmapするということか。
.find(_.isFalsified).getOrElse(Passed)では、最初に失敗にぶつかるとそこでストップ?
def buildMsg[A](s: A, e: Exception): String =
s"test case: $s\n" +
s"generated an exception: ${e.getMessage}\n" +
s"stack trace:\n ${e.getStackTrace.mkString("\n")}"
2015年6月14日日曜日
scala関数型デザイン&プログラミング P162
値を生成した後、その値にもとづいて次に使用するジェネレータを決定する、すなわち
ジェネレータを別のジェネレータに依存させるためにはflatMapが必要ということのようだ。
Exercise6.6 flatMapを実装し、それを使ってもう少し動的なlistOfNを実装せよ。Genクラスに配置。
def flatMap[B](f: A => Gen[B]): Gen[B] =
Gen(sample.flatMap(a => f(a).sample))
ここでsample.flatMapのsampleはState[RNG,A]で、f(a):Gen[B]だからf(a).sampleはState[RNG,B]
ということか?とすればGenのカッコの中はState[RNG,B]だからGen[B]が返されている。
def listOfN(size: Int): Gen[List[A]] =
Gen.listOfN(size, this)
これを使うと、下のようになる?
def listOfN(size: Gen[Int]): Gen[List[A]] =
size flatMap (n => this.listOfN(n))
わかったような、わからないような。。難しい
ジェネレータを別のジェネレータに依存させるためにはflatMapが必要ということのようだ。
Exercise6.6 flatMapを実装し、それを使ってもう少し動的なlistOfNを実装せよ。Genクラスに配置。
def flatMap[B](f: A => Gen[B]): Gen[B] =
Gen(sample.flatMap(a => f(a).sample))
ここでsample.flatMapのsampleはState[RNG,A]で、f(a):Gen[B]だからf(a).sampleはState[RNG,B]
ということか?とすればGenのカッコの中はState[RNG,B]だからGen[B]が返されている。
def listOfN(size: Int): Gen[List[A]] =
Gen.listOfN(size, this)
これを使うと、下のようになる?
def listOfN(size: Gen[Int]): Gen[List[A]] =
size flatMap (n => this.listOfN(n))
わかったような、わからないような。。難しい
scala関数型デザイン&プログラミング P161
case class Gen[A](sample:State[RNG,A])
Exercise8.4 Genの上記の表現を使って、startからstopExclusiveの範囲内の整数を生成するchooseを実装せよ
def choose(start: Int, stopExclusive: Int): Gen[Int] =
Gen(State(RNG.nonNegativeInt).map(n => start + n % (stopExclusive-start)))
Stateの中身を忘れていて、もう一度、前のところを読み直さないとよくわからなくなっている。
Exercise6.10のmapを確認すると def map[B](f: A => B): State[S, B] ということだから
StateのnonNegativeInt:Aが範囲内の整数:Bに変換されState[S,B]になっている。
Exercise8.5
def unit[A](a: => A): Gen[A] =
Gen(State.unit(a))
def boolean: Gen[Boolean] =
Gen(State(RNG.boolean))
booleanという関数が見当たらないような気がするが。。
def listOfN[A](n: Int, g: Gen[A]): Gen[List[A]] =
Gen(State.sequence(List.fill(n)(g.sample)))
Exercise8.4 Genの上記の表現を使って、startからstopExclusiveの範囲内の整数を生成するchooseを実装せよ
def choose(start: Int, stopExclusive: Int): Gen[Int] =
Gen(State(RNG.nonNegativeInt).map(n => start + n % (stopExclusive-start)))
Stateの中身を忘れていて、もう一度、前のところを読み直さないとよくわからなくなっている。
Exercise6.10のmapを確認すると def map[B](f: A => B): State[S, B] ということだから
StateのnonNegativeInt:Aが範囲内の整数:Bに変換されState[S,B]になっている。
Exercise8.5
def unit[A](a: => A): Gen[A] =
Gen(State.unit(a))
def boolean: Gen[Boolean] =
Gen(State(RNG.boolean))
booleanという関数が見当たらないような気がするが。。
def listOfN[A](n: Int, g: Gen[A]): Gen[List[A]] =
Gen(State.sequence(List.fill(n)(g.sample)))
scala関数型デザイン&プログラミング P149~151
Exercise7.11 choiceNを実装し、choiceNをベースにchoiceを実装せよ.
def choiceN[A](n:Par[Int])(choices:List[Par[A]]):Par[A]=
es => {
val ind = run(es)(n).get
run(es)(choices(ind))
}
run(es)(n).getで ind:Intを返している。choices(ind)はind番目のListの要素であるPar[A]を表す。
(chices.apply(ind)の省略形らしい)
def choice[A](cond:Par[Boolean])(t:Par[A],f:Par[A]):Par[A]=
choiceN(map(cond)(b => if (b) 0 else 1))(List(t, f))
Exercise7.12 リストの代わりにそれらのMapを使った場合はどうなるか。
def choiceMap[K,V](key: Par[K])(choices: Map[K,Par[V]]): Par[V] =
es => {
val k = run(es)(key).get
run(es)(choices(k))
}
Exercise7.13 新しいプリミティブchooserを実装し、これを使ってchoiceとchoiceNを実装せよ。
def chooser[A,B](p: Par[A])(choices: A => Par[B]): Par[B] =
es => {
val k = run(es)(p).get
run(es)(choices(k))
}
これが、じつはflatMapであるという説明のようです。
def flatMap[A,B](p: Par[A])(choices: A => Par[B]): Par[B] =
es => {
val k = run(es)(p).get
run(es)(choices(k))
}
def choiceViaFlatMap[A](p: Par[Boolean])(f: Par[A], t: Par[A]): Par[A] =
flatMap(p)(b => if (b) t else f)
def choiceNViaFlatMap[A](p: Par[Int])(choices: List[Par[A]]): Par[A] =
flatMap(p)(i => choices(i))
Exercise7.14 joinを実装せよ。joinを使ってflatMapを実装する方法はわかるか。またflatMapを使ってjoinを実装することは可能か。
def join[A](a: Par[Par[A]]): Par[A] =
es => run(es)(run(es)(a).get())
def joinViaFlatMap[A](a: Par[Par[A]]): Par[A] =
flatMap(a)(x => x)
def flatMapViaJoin[A,B](p: Par[A])(f: A => Par[B]): Par[B] =
join(map(p)(f))
最後のjoin(map(p)(f))は、型をたどれば矛盾ない感じはするが、いまいちすっきり理解できてない
def choiceN[A](n:Par[Int])(choices:List[Par[A]]):Par[A]=
es => {
val ind = run(es)(n).get
run(es)(choices(ind))
}
run(es)(n).getで ind:Intを返している。choices(ind)はind番目のListの要素であるPar[A]を表す。
(chices.apply(ind)の省略形らしい)
def choice[A](cond:Par[Boolean])(t:Par[A],f:Par[A]):Par[A]=
choiceN(map(cond)(b => if (b) 0 else 1))(List(t, f))
Exercise7.12 リストの代わりにそれらのMapを使った場合はどうなるか。
def choiceMap[K,V](key: Par[K])(choices: Map[K,Par[V]]): Par[V] =
es => {
val k = run(es)(key).get
run(es)(choices(k))
}
Exercise7.13 新しいプリミティブchooserを実装し、これを使ってchoiceとchoiceNを実装せよ。
def chooser[A,B](p: Par[A])(choices: A => Par[B]): Par[B] =
es => {
val k = run(es)(p).get
run(es)(choices(k))
}
これが、じつはflatMapであるという説明のようです。
def flatMap[A,B](p: Par[A])(choices: A => Par[B]): Par[B] =
es => {
val k = run(es)(p).get
run(es)(choices(k))
}
def choiceViaFlatMap[A](p: Par[Boolean])(f: Par[A], t: Par[A]): Par[A] =
flatMap(p)(b => if (b) t else f)
def choiceNViaFlatMap[A](p: Par[Int])(choices: List[Par[A]]): Par[A] =
flatMap(p)(i => choices(i))
Exercise7.14 joinを実装せよ。joinを使ってflatMapを実装する方法はわかるか。またflatMapを使ってjoinを実装することは可能か。
def join[A](a: Par[Par[A]]): Par[A] =
es => run(es)(run(es)(a).get())
def joinViaFlatMap[A](a: Par[Par[A]]): Par[A] =
flatMap(a)(x => x)
def flatMapViaJoin[A,B](p: Par[A])(f: A => Par[B]): Par[B] =
join(map(p)(f))
最後のjoin(map(p)(f))は、型をたどれば矛盾ない感じはするが、いまいちすっきり理解できてない
scala関数型デザイン&プログラミング P143
リスト7-11
def run[A](es: ExecutorService)(p: Par[A]): A = {
val ref = new java.util.concurrent.atomic.AtomicReference[A]
val latch = new CountDownLatch(1)
p(es) { a => ref.set(a); latch.countDown }
latch.await
ref.get
}
p(es) { a => ref.set(a); latch.countDown } の意味がすぐにはわからなかった。
trait Future[+A] {
private[parallelism] def apply(k: A => Unit): Unit
}
type Par[+A] = ExecutorService => Future[A]
を参照すると
pがPar[A]で es=>Futre[A]なので p(es)はFuture[A]を表す。
Future[A]のapplyはA=>Unitを引数としているので、 { a => ref.set(a); latch.countDown } を適用しているようだ。
def run[A](es: ExecutorService)(p: Par[A]): A = {
val ref = new java.util.concurrent.atomic.AtomicReference[A]
val latch = new CountDownLatch(1)
p(es) { a => ref.set(a); latch.countDown }
latch.await
ref.get
}
p(es) { a => ref.set(a); latch.countDown } の意味がすぐにはわからなかった。
trait Future[+A] {
private[parallelism] def apply(k: A => Unit): Unit
}
type Par[+A] = ExecutorService => Future[A]
を参照すると
pがPar[A]で es=>Futre[A]なので p(es)はFuture[A]を表す。
Future[A]のapplyはA=>Unitを引数としているので、 { a => ref.set(a); latch.countDown } を適用しているようだ。
2015年6月13日土曜日
scala関数型デザイン&プログラミング P134
Exercise 7.6 リストの要素を並行してフィルタリングするparFilterを実装せよ。
解答は
def parFilter[A](l: List[A])(f: A => Boolean): Par[List[A]] = {
val pars: List[Par[List[A]]] =
l map (asyncF((a: A) => if (f(a)) List(a) else List()))
map(sequence(pars))(_.flatten)
}
asyncF( (a: A) => if (f(a)) List(a) else List() ) の部分を見ると
def asyncF(f:A=>B):A=>Par[B] なので 返り値は A=>Par[List[A]]となっている。
したがって、
l map (asyncF((a: A) => if (f(a)) List(a) else List())) により List[Par[List[A]]]になることがわかる。
これをsequenceの引数とすれば,Par[List[List[A]]]に変換される。
flattenはリストの結合なので、Par[List[A]]となるようだ。
解答は
def parFilter[A](l: List[A])(f: A => Boolean): Par[List[A]] = {
val pars: List[Par[List[A]]] =
l map (asyncF((a: A) => if (f(a)) List(a) else List()))
map(sequence(pars))(_.flatten)
}
asyncF( (a: A) => if (f(a)) List(a) else List() ) の部分を見ると
def asyncF(f:A=>B):A=>Par[B] なので 返り値は A=>Par[List[A]]となっている。
したがって、
l map (asyncF((a: A) => if (f(a)) List(a) else List())) により List[Par[List[A]]]になることがわかる。
これをsequenceの引数とすれば,Par[List[List[A]]]に変換される。
flattenはリストの結合なので、Par[List[A]]となるようだ。
scala関数型デザイン&プログラミング P134
Exercise 7.5 このsequenceという関数を記述せよ。追加のプリミティブは必要ない。runを呼び出さないこと。
def sequence[A](ps:List[Par[A]]):Par[List[A]]
いろいろ解答例がでていた。
def sequence_simple[A](l: List[Par[A]]): Par[List[A]] =
l.foldRight[Par[List[A]]](unit(List()))((h,t) => map2(h,t)(_ :: _))
このfoldRightを使う方法は、すでにこれまでにもでてきたパターン。
def sequenceRight[A](as: List[Par[A]]): Par[List[A]] =
as match {
case Nil => unit(Nil)
case h :: t => map2(h, fork(sequence(t)))(_ :: _)
}
こちらは、効率いい方法ということのようだけれど、難しい。
def sequenceBalanced[A](as: IndexedSeq[Par[A]]): Par[IndexedSeq[A]] = fork {
if (as.isEmpty) unit(Vector())
else if (as.length == 1) map(as.head)(a => Vector(a))
else {
val (l,r) = as.splitAt(as.length/2)
map2(sequenceBalanced(l), sequenceBalanced(r))(_ ++ _)
}
}
def sequence[A](as: List[Par[A]]): Par[List[A]] =
map(sequenceBalanced(as.toIndexedSeq))(_.toList)
def sequence[A](ps:List[Par[A]]):Par[List[A]]
いろいろ解答例がでていた。
def sequence_simple[A](l: List[Par[A]]): Par[List[A]] =
l.foldRight[Par[List[A]]](unit(List()))((h,t) => map2(h,t)(_ :: _))
このfoldRightを使う方法は、すでにこれまでにもでてきたパターン。
def sequenceRight[A](as: List[Par[A]]): Par[List[A]] =
as match {
case Nil => unit(Nil)
case h :: t => map2(h, fork(sequence(t)))(_ :: _)
}
こちらは、効率いい方法ということのようだけれど、難しい。
def sequenceBalanced[A](as: IndexedSeq[Par[A]]): Par[IndexedSeq[A]] = fork {
if (as.isEmpty) unit(Vector())
else if (as.length == 1) map(as.head)(a => Vector(a))
else {
val (l,r) = as.splitAt(as.length/2)
map2(sequenceBalanced(l), sequenceBalanced(r))(_ ++ _)
}
}
def sequence[A](as: List[Par[A]]): Par[List[A]] =
map(sequenceBalanced(as.toIndexedSeq))(_.toList)
scala関数型デザイン&プログラミング P131
Exercise7.3 map2を修正し、Futureのタイムアウトの規約に従うようにせよ。
javaをよく理解してなこともあり、コードを読み取るのが難しい。
Map2Futureの中にある@volatileは、「あるスレッドで更新された値が別スレッドで読み込まれる」ことが保証されるのだそうだ。
chache.isDefinedはOption[C]のcacheがSomeかNoneかを表す。
afの評価にかかった時間を記録し、bfの評価に割り当てられた時間からその時間を引くという操作が、val br = b.get(timeoutMs - at, TimeUnit.MILLISECONDS)の部分か?
def map2[A,B,C](a: Par[A], b: Par[B])(f: (A,B) => C): Par[C] =
es => {
val (af, bf) = (a(es), b(es))
Map2Future(af, bf, f)
}
case class Map2Future[A,B,C](a: Future[A], b: Future[B],
f: (A,B) => C) extends Future[C] {
@volatile var cache: Option[C] = None
def isDone = cache.isDefined
def isCancelled = a.isCancelled || b.isCancelled
def cancel(evenIfRunning: Boolean) =
a.cancel(evenIfRunning) || b.cancel(evenIfRunning)
def get = compute(Long.MaxValue)
def get(timeout: Long, units: TimeUnit): C =
compute(TimeUnit.MILLISECONDS.convert(timeout, units))
private def compute(timeoutMs: Long): C = cache match {
case Some(c) => c
case None =>
val start = System.currentTimeMillis
val ar = a.get(timeoutMs, TimeUnit.MILLISECONDS)
val stop = System.currentTimeMillis; val at = stop-start
val br = b.get(timeoutMs - at, TimeUnit.MILLISECONDS)
val ret = f(ar, br)
cache = Some(ret)
ret
}
}
Exercise7.4 lazyUnitを使って関数を記述せよ。この関数は任意の関数A=>Bから、その結果を非同期で評価する関数へと変換する。
def asyncF[A,B](f:A=>B):A=>Par[B]=
a => lazyUnit(f(a))
javaをよく理解してなこともあり、コードを読み取るのが難しい。
Map2Futureの中にある@volatileは、「あるスレッドで更新された値が別スレッドで読み込まれる」ことが保証されるのだそうだ。
chache.isDefinedはOption[C]のcacheがSomeかNoneかを表す。
afの評価にかかった時間を記録し、bfの評価に割り当てられた時間からその時間を引くという操作が、val br = b.get(timeoutMs - at, TimeUnit.MILLISECONDS)の部分か?
def map2[A,B,C](a: Par[A], b: Par[B])(f: (A,B) => C): Par[C] =
es => {
val (af, bf) = (a(es), b(es))
Map2Future(af, bf, f)
}
case class Map2Future[A,B,C](a: Future[A], b: Future[B],
f: (A,B) => C) extends Future[C] {
@volatile var cache: Option[C] = None
def isDone = cache.isDefined
def isCancelled = a.isCancelled || b.isCancelled
def cancel(evenIfRunning: Boolean) =
a.cancel(evenIfRunning) || b.cancel(evenIfRunning)
def get = compute(Long.MaxValue)
def get(timeout: Long, units: TimeUnit): C =
compute(TimeUnit.MILLISECONDS.convert(timeout, units))
private def compute(timeoutMs: Long): C = cache match {
case Some(c) => c
case None =>
val start = System.currentTimeMillis
val ar = a.get(timeoutMs, TimeUnit.MILLISECONDS)
val stop = System.currentTimeMillis; val at = stop-start
val br = b.get(timeoutMs - at, TimeUnit.MILLISECONDS)
val ret = f(ar, br)
cache = Some(ret)
ret
}
}
Exercise7.4 lazyUnitを使って関数を記述せよ。この関数は任意の関数A=>Bから、その結果を非同期で評価する関数へと変換する。
def asyncF[A,B](f:A=>B):A=>Par[B]=
a => lazyUnit(f(a))
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にせず、もっと汎用的にしなさいということのようだ。
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にせず、もっと汎用的にしなさいということのようだ。
2015年6月8日月曜日
scala関数型デザイン&プログラミング P112
exercise 6.11 Stateの使用に慣れるために、単純なスナックの自動販売機をモデリングする有限状態オートマンを実装せよ。この自動販売機では、2種類の入力を使用する。すなわち硬貨を投入することができ、ハンドルを回してスナックを取り出すことができる。自動販売機はロックされた状態とロックが解除された状態のどちらかになる。また、残りのスナックの数と自動販売機に投入された硬貨の数も追跡する。
解答は次のようになっている。書籍で断っている通り難問。sequenceの使い方がいまいちわからない。inputsからのi:Inputを逐次処理していくのだろうか。modfyで、状態を変化させるんだろうけれど。これだけの式で、List[Input]の中のInputをすべて逐次処理して、最終結果をs<-getで得るということなんだろうか?
sealed trait Input
case object Coin extends Input
case object Turn extends Input
case class Machine(locked:Boolean,candies:Int,conis:Int)
object Candy {
def simulateMachine(inputs: List[Input]): State[Machine, (Int, Int)] = for {
_ <- sequence(inputs.map(i => modify((s: Machine) => (i, s) match {
case (_, Machine(_, 0, _)) => s
case (Coin, Machine(false, _, _)) => s
case (Turn, Machine(true, _, _)) => s
case (Coin, Machine(true, candy, coin)) =>
Machine(false, candy, coin + 1)
case (Turn, Machine(false, candy, coin)) =>
Machine(true, candy - 1, coin)
})))
s <- get
} yield (s.coins, s.candies)
}
解答は次のようになっている。書籍で断っている通り難問。sequenceの使い方がいまいちわからない。inputsからのi:Inputを逐次処理していくのだろうか。modfyで、状態を変化させるんだろうけれど。これだけの式で、List[Input]の中のInputをすべて逐次処理して、最終結果をs<-getで得るということなんだろうか?
sealed trait Input
case object Coin extends Input
case object Turn extends Input
case class Machine(locked:Boolean,candies:Int,conis:Int)
object Candy {
def simulateMachine(inputs: List[Input]): State[Machine, (Int, Int)] = for {
_ <- sequence(inputs.map(i => modify((s: Machine) => (i, s) match {
case (_, Machine(_, 0, _)) => s
case (Coin, Machine(false, _, _)) => s
case (Turn, Machine(true, _, _)) => s
case (Coin, Machine(true, candy, coin)) =>
Machine(false, candy, coin + 1)
case (Turn, Machine(false, candy, coin)) =>
Machine(true, candy - 1, coin)
})))
s <- get
} yield (s.coins, s.candies)
}
2015年6月7日日曜日
scala関数型デザイン&プログラミング P110
Exercise 6.10 unit,map2,flatMap,sequenceの5つの関数を一般化せよ。
case class State[S, +A](run: S => (A, S)) {
def flatMap[B](f: A => State[S, B]): State[S, B] = State(s=> {
val (a,st)=run(s)
f(a)(st)
})
// runという関数は、S=>(A,S)なので、run(s)により(a,st)を返す
//f:A=>State[S,B]だから f(a)はState[S,B]すなわちS=>(A,S)という関数であり、引数は今の場合st:S
//をもってくるとよい。したがってf(a)(st)
def map[B](f: A => B): State[S, B] =
flatMap(a=> unit(f(a)) )
def map2[B,C](sb: State[S, B])(f: (A, B) => C): State[S, C] =
flatMap(a => sb.map(b =>f(a,b)))
//State[S,C] S=>(C,S)という関数が返値 b=>f(a,b)つまりb=>cをmapに適用する
// と State[S,B]がState[S,C]に変換される flatMap(f:A=>State[S,C]):State[S,C]という型になっている
}
object State {
def unit[S, A](a: A): State[S, A] =
State(s => (a, s))
def sequenceViaFoldRight[S,A](sas: List[State[S, A]]): State[S, List[A]] =
sas.foldRight(unit[S, List[A]](List()))((f, acc) => f.map2(acc)(_ :: _))
//ここで、folrRightを復習してみた。
//def foldRight[A,B](as:List[A],z:B)(f:(A,B)=>B):Bだった。
// (f, acc) => map2(f, acc)(_ :: _) では
// f.map2(acc)(_::_)が f:State[S,A]とacc:State[S,List[A]]を結合して、新たに State[S,List[A]]を返す
//fにはsas:List[State[S,A]]から State[S,A]をひとつずつ切り取ってくる感じ?けっこう難しい。
}
case classとobjectに分けて実装しているが、その理由など、基本的なことがまだよくわかってない。
case class State[S, +A](run: S => (A, S)) {
def flatMap[B](f: A => State[S, B]): State[S, B] = State(s=> {
val (a,st)=run(s)
f(a)(st)
})
// runという関数は、S=>(A,S)なので、run(s)により(a,st)を返す
//f:A=>State[S,B]だから f(a)はState[S,B]すなわちS=>(A,S)という関数であり、引数は今の場合st:S
//をもってくるとよい。したがってf(a)(st)
def map[B](f: A => B): State[S, B] =
flatMap(a=> unit(f(a)) )
def map2[B,C](sb: State[S, B])(f: (A, B) => C): State[S, C] =
flatMap(a => sb.map(b =>f(a,b)))
//State[S,C] S=>(C,S)という関数が返値 b=>f(a,b)つまりb=>cをmapに適用する
// と State[S,B]がState[S,C]に変換される flatMap(f:A=>State[S,C]):State[S,C]という型になっている
}
object State {
def unit[S, A](a: A): State[S, A] =
State(s => (a, s))
def sequenceViaFoldRight[S,A](sas: List[State[S, A]]): State[S, List[A]] =
sas.foldRight(unit[S, List[A]](List()))((f, acc) => f.map2(acc)(_ :: _))
//ここで、folrRightを復習してみた。
//def foldRight[A,B](as:List[A],z:B)(f:(A,B)=>B):Bだった。
// (f, acc) => map2(f, acc)(_ :: _) では
// f.map2(acc)(_::_)が f:State[S,A]とacc:State[S,List[A]]を結合して、新たに State[S,List[A]]を返す
//fにはsas:List[State[S,A]]から State[S,A]をひとつずつ切り取ってくる感じ?けっこう難しい。
}
case classとobjectに分けて実装しているが、その理由など、基本的なことがまだよくわかってない。
2015年6月4日木曜日
scala関数型デザイン&プログラミング P108
Exercise 6.8
flatMapを実装し、それを使ってnonNegativeLessThanを実装せよ。
def flatmap[A,B](f:Rand[A])(g:A=>Rand[B]):Rand[B] = { rng =>
val (a,rng2)=f(rng)
g(a)(rng2)
}
まず、fはRand[A]の型、つまり rng=>(a,rng2)を表す。したがって、val (a,rng2)=f(rng)となる。
つぎに、g:A=>Rand[B]より g(a)がRand[B]を表す。これにrng2を適用したg(a)(rng2)が返り値
そして、最終的に、flatMapの返り値は、{rng=>g(a)(rng2)}で、これはRand[B]
def nonNegativeLessThan2(n:Int):Rand[Int] =
flatMap(nonNegativeInt)(i=>
val mod=i%n
if (i+(n-1)-mod>=0)
unit(mode)
else
nonNegativeLessThan2(n)
)
flatMapの第1引数は、Rand[A]なので、nonNegativeInt:Rand[Int]という関数でいい。
次に、第2引数は、A=>Rand[B]という型の関数。AはInt、つまり変数iとして、これを引数として
Rand[B]が返り値になるような関数を記述するとよい。
この場合の返り値の計算は (i+(n-1)-mod)がTrueなら、unit(mode)つまり、rngが変化せず、(mode,rng)をそのまま返すような関数。falseならば、リトライする関数となる。
Exercise 6.9 flatMapを使ってmap,map2を再実装せよ。
def _map[A,B](s:Rand[A])(f:A=>B):Rand[B]=
flatMap(s)(a=>unit(f(a))
unitを使えばA=>Rand[B]の部分をうまく表せる
def _map2[A,B,C](ra:Rand[A],rb:Rand[B])(f:(A,B)=>C):Rand[C] =
flatMap(ra)(a => map(rb)(b => f(a, b)))
こちらは解答例。 ra,rbのふたつ同時には変換は無理なので mapを使うとひとつずつできる。
flatMapを実装し、それを使ってnonNegativeLessThanを実装せよ。
def flatmap[A,B](f:Rand[A])(g:A=>Rand[B]):Rand[B] = { rng =>
val (a,rng2)=f(rng)
g(a)(rng2)
}
まず、fはRand[A]の型、つまり rng=>(a,rng2)を表す。したがって、val (a,rng2)=f(rng)となる。
つぎに、g:A=>Rand[B]より g(a)がRand[B]を表す。これにrng2を適用したg(a)(rng2)が返り値
そして、最終的に、flatMapの返り値は、{rng=>g(a)(rng2)}で、これはRand[B]
def nonNegativeLessThan2(n:Int):Rand[Int] =
flatMap(nonNegativeInt)(i=>
val mod=i%n
if (i+(n-1)-mod>=0)
unit(mode)
else
nonNegativeLessThan2(n)
)
flatMapの第1引数は、Rand[A]なので、nonNegativeInt:Rand[Int]という関数でいい。
次に、第2引数は、A=>Rand[B]という型の関数。AはInt、つまり変数iとして、これを引数として
Rand[B]が返り値になるような関数を記述するとよい。
この場合の返り値の計算は (i+(n-1)-mod)がTrueなら、unit(mode)つまり、rngが変化せず、(mode,rng)をそのまま返すような関数。falseならば、リトライする関数となる。
Exercise 6.9 flatMapを使ってmap,map2を再実装せよ。
def _map[A,B](s:Rand[A])(f:A=>B):Rand[B]=
flatMap(s)(a=>unit(f(a))
unitを使えばA=>Rand[B]の部分をうまく表せる
def _map2[A,B,C](ra:Rand[A],rb:Rand[B])(f:(A,B)=>C):Rand[C] =
flatMap(ra)(a => map(rb)(b => f(a, b)))
こちらは解答例。 ra,rbのふたつ同時には変換は無理なので mapを使うとひとつずつできる。
2015年6月3日水曜日
scala関数型デザイン&プログラミング P107
def nonNegativeLessThan(n:Int):Rand[Int]=
map(nonNegativeInt) { i=>
val mod = i % n
if (i + (n-1) -mod >= 0) mod else nonNegaativeLessThan(n)(???)
i+(n-1)-mod>=0がnの最大の倍数より大きいことを意味するといっているが、わかりにくい。
i-modは、nの倍数だが、これが、最大の倍数でないならば、これにn-1をたしても、32ビット整数におさまる。(つまり>=0ということか?)しかし、最大の倍数ならば、これにn-1を足すと、<0になるということなんだろうか?そして、<0ということは、i-modが最大の倍数なので、iが最大の倍数より大きい数であり、nonNegativeLessThanをリトライする。と理解したがいいんだろうか?
map(nonNegativeInt) { i=>
val mod = i % n
if (i + (n-1) -mod >= 0) mod else nonNegaativeLessThan(n)(???)
i+(n-1)-mod>=0がnの最大の倍数より大きいことを意味するといっているが、わかりにくい。
i-modは、nの倍数だが、これが、最大の倍数でないならば、これにn-1をたしても、32ビット整数におさまる。(つまり>=0ということか?)しかし、最大の倍数ならば、これにn-1を足すと、<0になるということなんだろうか?そして、<0ということは、i-modが最大の倍数なので、iが最大の倍数より大きい数であり、nonNegativeLessThanをリトライする。と理解したがいいんだろうか?
2015年6月2日火曜日
scala関数型デザイン&プログラミング P106
Exercise 6.6 以下のシグネチャに基づいてmap2を実施せよ。この関数は、raとrbの2つのアクションと、それらの結果を結合する関数fを受け取り、それらを結合する新しいアクションを返す。
def map2[A,B,C](ra: Rand[A], rb: Rand[B])(f: (A, B) => C): Rand[C] =
rng => {
val (a,rng2)=ra(rng)
val (b,rng3)=rb(rng2)
(f(a,b),rng3)
}
Exercise 6.7 2つのRNG遷移の組み合わせが可能であるとしたら、それらのリストを結合することも可能であるはずだ。遷移のListを1つの遷移にまとめるためのsequenceを実装せよ。それを使って、以前記述したints関数を再実装せよ。その際には、標準ライブラリのList.fill(n)(x)関数を使ってxをn回繰り返すリストを作成できる。
解答は
def sequence[A](fs: List[Rand[A]]): Rand[List[A]] =
fs.foldRight(unit( List[A]() )) ( (f, acc) => map2(f, acc)(_ :: _) )
unit(List[A]())は rng=>(List[A](),rng) で Rand[List[A]]
(f, acc) => map2(f, acc)(_ :: _) では
map2(f,acc)(_::_)が f:Rand[A]とacc:Rand[List[A]]を結合して、新たに Rand[List[A]]を返す
fにはfs:List[Rand[A]]から Rand[A]をひとつずつ切り取ってくる感じだろうか。。
確かに、これは難問
def _ints(count: Int): Rand[List[Int]] =
sequence(List.fill(count)(int))
val int:Rand[Int] = _.nextInt で乱数を発生 それをcount回繰り返すリスト(List[Rand[Int]])を作成している。 そして、それをsequenceでRand[List[Int]]に変換している。
def map2[A,B,C](ra: Rand[A], rb: Rand[B])(f: (A, B) => C): Rand[C] =
rng => {
val (a,rng2)=ra(rng)
val (b,rng3)=rb(rng2)
(f(a,b),rng3)
}
Exercise 6.7 2つのRNG遷移の組み合わせが可能であるとしたら、それらのリストを結合することも可能であるはずだ。遷移のListを1つの遷移にまとめるためのsequenceを実装せよ。それを使って、以前記述したints関数を再実装せよ。その際には、標準ライブラリのList.fill(n)(x)関数を使ってxをn回繰り返すリストを作成できる。
解答は
def sequence[A](fs: List[Rand[A]]): Rand[List[A]] =
fs.foldRight(unit( List[A]() )) ( (f, acc) => map2(f, acc)(_ :: _) )
unit(List[A]())は rng=>(List[A](),rng) で Rand[List[A]]
(f, acc) => map2(f, acc)(_ :: _) では
map2(f,acc)(_::_)が f:Rand[A]とacc:Rand[List[A]]を結合して、新たに Rand[List[A]]を返す
fにはfs:List[Rand[A]]から Rand[A]をひとつずつ切り取ってくる感じだろうか。。
確かに、これは難問
def _ints(count: Int): Rand[List[Int]] =
sequence(List.fill(count)(int))
val int:Rand[Int] = _.nextInt で乱数を発生 それをcount回繰り返すリスト(List[Rand[Int]])を作成している。 そして、それをsequenceでRand[List[Int]]に変換している。
2015年5月31日日曜日
scala関数型デザイン&プログラミング P105
Exercise 6.5 mapを使ってdoubleを実装し直せ
val rng = new scala.util.Random
trait RNG{
def nextInt:(Int,RNG)
}
case class SimpleRNG(seed: Long) extends RNG {
def nextInt:(Int,RNG) = {
val newSeed =(seed * 0x5DEECE66DL+0xBL) & 0xFFFFFFFFFFFFL
val nextRNG= SimpleRNG(newSeed)
val n = (newSeed >>>16).toInt
(n,nextRNG)
}
}
def nonNegativeInt(rng: RNG): (Int, RNG) = {
val (i, r) = rng.nextInt
(if (i < 0) -(i + 1) else i, r)
}
type Rand[+A]=RNG=>(A,RNG)
def map [A,B](s:Rand[A])(f:A=>B):Rand[B]=
rng=>{
val (a,rng2) = s(rng)
(f(a),rng2)
}
def _double(rng:RNG):Rand[Double] =
map (nonNegativeInt)(_/(Int.MaxValue.toDouble+1))
val (a,rng2) = _double(rng)(rng)で確認
val rng = new scala.util.Random
trait RNG{
def nextInt:(Int,RNG)
}
case class SimpleRNG(seed: Long) extends RNG {
def nextInt:(Int,RNG) = {
val newSeed =(seed * 0x5DEECE66DL+0xBL) & 0xFFFFFFFFFFFFL
val nextRNG= SimpleRNG(newSeed)
val n = (newSeed >>>16).toInt
(n,nextRNG)
}
}
def nonNegativeInt(rng: RNG): (Int, RNG) = {
val (i, r) = rng.nextInt
(if (i < 0) -(i + 1) else i, r)
}
type Rand[+A]=RNG=>(A,RNG)
def map [A,B](s:Rand[A])(f:A=>B):Rand[B]=
rng=>{
val (a,rng2) = s(rng)
(f(a),rng2)
}
def _double(rng:RNG):Rand[Double] =
map (nonNegativeInt)(_/(Int.MaxValue.toDouble+1))
val (a,rng2) = _double(rng)(rng)で確認
2015年5月30日土曜日
scala関数型デザイン&プログラミング P103
Exercise 6.4 ランダムな整数のリストを生成する関数を記述せよ。
解答によれば
def ints(count: Int)(rng: RNG): (List[Int], RNG) =
if (count <= 0)
(List(), rng)
else {
val (x, r1) = rng.nextInt
val (xs, r2) = ints(count - 1)(r1)
(x :: xs, r2)
}
以下rngは略して、トレースしてみると
ints(0)()=(List(),rng)
ints(1)()=(x::List(), )
ints(2)()=(x::x::List(),)
と続くことになるようだ。
解答によれば
def ints(count: Int)(rng: RNG): (List[Int], RNG) =
if (count <= 0)
(List(), rng)
else {
val (x, r1) = rng.nextInt
val (xs, r2) = ints(count - 1)(r1)
(x :: xs, r2)
}
以下rngは略して、トレースしてみると
ints(0)()=(List(),rng)
ints(1)()=(x::List(), )
ints(2)()=(x::x::List(),)
と続くことになるようだ。
2015年5月28日木曜日
scala関数型デザイン&プログラミング P93
Exersise 5.12 unfoldを使ってmap,take,takeWhile,zipWith,zipAllを実装せよ。zipAll関数ではどちらかのストリームに要素が残っている限り、評価を続ける必要がある。(ストリームが完全に評価されたかどうかを示すのにOptionを使用する)
def map3[B](f:A=>B):Stream[B] =
unfold(this)( p=>p match {case Cons(a,as)=>Some(f(a()),as())
case _ => None
})
省略形にすると
def map4[B](f:A=>B):Stream[B] =
unfold(this) {case Cons(a,as)=>Some(f(a()),as())
case _ => None
}
def take2(n:Int):Stream[A]=
unfold((this,n)) {
case (Cons(a,as),n) if (n>0) => Some( (a(),(as(),n-1)) )
case _ => None
}
def takeWhile4(p:A=>Boolean):Stream[A] =
unfold(this) {
case (Cons(a,as)) if (p(a())) => Some(a(),as())
case _ => None
}
def zipWith2[A](as:Stream[A],bs:Stream[A])(f:(A,A)=>A):Stream[A]=
unfold(as,bs) {
case (Cons(a,as),Cons(b,bs)) => Some(f(a(),b()),(as(),bs()))
case (_,_)=>None
}
def zipAll[B](s2:Stream[B]):Stream[(Option[A],Option[B])] =
unfold(this,s2) {
case (Cons(a,as),Cons(b,bs)) => Some((Some(a()),Some(b())),(as(),bs()))
ここで、はたと止まってしまった。
case(Empty,Cons(b,bs))=>Some、、、、のところがどうしてもうまくいかない。
解答のプログラムもコンパイルしてみたが、エラーが発生する。
def map3[B](f:A=>B):Stream[B] =
unfold(this)( p=>p match {case Cons(a,as)=>Some(f(a()),as())
case _ => None
})
省略形にすると
def map4[B](f:A=>B):Stream[B] =
unfold(this) {case Cons(a,as)=>Some(f(a()),as())
case _ => None
}
def take2(n:Int):Stream[A]=
unfold((this,n)) {
case (Cons(a,as),n) if (n>0) => Some( (a(),(as(),n-1)) )
case _ => None
}
def takeWhile4(p:A=>Boolean):Stream[A] =
unfold(this) {
case (Cons(a,as)) if (p(a())) => Some(a(),as())
case _ => None
}
def zipWith2[A](as:Stream[A],bs:Stream[A])(f:(A,A)=>A):Stream[A]=
unfold(as,bs) {
case (Cons(a,as),Cons(b,bs)) => Some(f(a(),b()),(as(),bs()))
case (_,_)=>None
}
def zipAll[B](s2:Stream[B]):Stream[(Option[A],Option[B])] =
unfold(this,s2) {
case (Cons(a,as),Cons(b,bs)) => Some((Some(a()),Some(b())),(as(),bs()))
ここで、はたと止まってしまった。
case(Empty,Cons(b,bs))=>Some、、、、のところがどうしてもうまくいかない。
解答のプログラムもコンパイルしてみたが、エラーが発生する。
2015年5月26日火曜日
scala関数型デザイン&プログラミング P93
Exercise 5.11 より汎用的なunfoldを記述せよ
解答をみるとf(z) matchとしている。柔軟な発想が必要なようだ。
def unfold[A, S](z: S)(f: S => Option[(A, S)]): Stream[A] =
f(z) match {
case Some((h,s)) => cons(h, unfold(s)(f))
case None => empty
}
これまで、でてきた生成関数に共通する部分をみると
def 自分自身(引数1)=cons(h,自分自身(引数2))
となっているので、引数1から引数2への変換のためにfという関数を用意し、同時にそのfの関数でhも求めるようにしている。
Exercise 5.12 fibs、from、constant,onesをunfoldを使って実装する。
def fibs4(n1:Int,n2:Int)=
unfold((n1,n2))( ((nn1,nn2)) => Some( (nn1,(nn2,nn1+nn2) ) ) )
としたが、なぜかエラー 1引数の関数にせよ。そのためにcaseパターンを使うということか?
解答のとおり
def fibs3(n1:Int,n2:Int)=
unfold((n1,n2))( p=>p match {case (nn1,nn2) => Some( (nn1,(nn2,nn1+nn2) ) ) } )
とするとうまくいく。 1引数としてpをとり、その戻り値がp match {case (nn1,nn2) => Some( (nn1,(nn2,nn1+nn2) ) ) } ということになるんだろうか。回りくどい感じがすると思うのは私だけだろうか。
省略形が
def fibs3(n1:Int,n2:Int)=
unfold((n1,n2)) {case (nn1,nn2) => Some( (nn1,(nn2,nn1+nn2) ) ) }
だとか。
これ以降はmatchは使わなくてもよいようだ。
def from2(n:Int):Stream[Int]= unfold(n)( n=>Some((n,n+1)) )
def constant2[A](a:A):Stream[A]= unfold(a)(a=>Some( (a , a ) ) )
def ones:Stream[Int]=unfold(1)(i=>Some((i,i)))
解答をみるとf(z) matchとしている。柔軟な発想が必要なようだ。
def unfold[A, S](z: S)(f: S => Option[(A, S)]): Stream[A] =
f(z) match {
case Some((h,s)) => cons(h, unfold(s)(f))
case None => empty
}
これまで、でてきた生成関数に共通する部分をみると
def 自分自身(引数1)=cons(h,自分自身(引数2))
となっているので、引数1から引数2への変換のためにfという関数を用意し、同時にそのfの関数でhも求めるようにしている。
Exercise 5.12 fibs、from、constant,onesをunfoldを使って実装する。
def fibs4(n1:Int,n2:Int)=
unfold((n1,n2))( ((nn1,nn2)) => Some( (nn1,(nn2,nn1+nn2) ) ) )
としたが、なぜかエラー 1引数の関数にせよ。そのためにcaseパターンを使うということか?
解答のとおり
def fibs3(n1:Int,n2:Int)=
unfold((n1,n2))( p=>p match {case (nn1,nn2) => Some( (nn1,(nn2,nn1+nn2) ) ) } )
とするとうまくいく。 1引数としてpをとり、その戻り値がp match {case (nn1,nn2) => Some( (nn1,(nn2,nn1+nn2) ) ) } ということになるんだろうか。回りくどい感じがすると思うのは私だけだろうか。
省略形が
def fibs3(n1:Int,n2:Int)=
unfold((n1,n2)) {case (nn1,nn2) => Some( (nn1,(nn2,nn1+nn2) ) ) }
だとか。
これ以降はmatchは使わなくてもよいようだ。
def from2(n:Int):Stream[Int]= unfold(n)( n=>Some((n,n+1)) )
def constant2[A](a:A):Stream[A]= unfold(a)(a=>Some( (a , a ) ) )
def ones:Stream[Int]=unfold(1)(i=>Some((i,i)))
scala関数型デザイン&プログラミング P92
Exercise 5.8 指定された値の無限ストリームconstant関数を記述せよ
def constant[A](a:A):Stream[A] =cons(a,constant(a))
解答は、次のようになっていた。これより効率のいい方法ということのようだ。
def constant[A](a: A): Stream[A] = {
lazy val tail: Stream[A] = Cons(() => a, () => tail)
tail
}
Exercise 5.9 nではじまり、n+1,n+2、、と続く無限ストリームを生成する関数を記述せよ
def from(n:Int):Stream[Int] = cons(n,from(n+1))
Exercise 5.10 フィボナッチ数列の無限ストリームを生成するfibs関数を記述せよ
def fibs(n1:Int,n2:Int):Stream[Int]=cons(n1,cons(n2,fibs(n1+n2,n1+2*n2)))
解答は
val fibs = {
def go(f0: Int, f1: Int): Stream[Int] =
cons(f0, go(f1, f0+f1))
go(0, 1)
}
これを見て
def fibs2(n1:Int,n2:Int):Stream[Int]=cons(n1,fibs2(n2,n1+n2))
でもいいのではないかと思ったが。。。
def constant[A](a:A):Stream[A] =cons(a,constant(a))
解答は、次のようになっていた。これより効率のいい方法ということのようだ。
def constant[A](a: A): Stream[A] = {
lazy val tail: Stream[A] = Cons(() => a, () => tail)
tail
}
Exercise 5.9 nではじまり、n+1,n+2、、と続く無限ストリームを生成する関数を記述せよ
def from(n:Int):Stream[Int] = cons(n,from(n+1))
Exercise 5.10 フィボナッチ数列の無限ストリームを生成するfibs関数を記述せよ
def fibs(n1:Int,n2:Int):Stream[Int]=cons(n1,cons(n2,fibs(n1+n2,n1+2*n2)))
解答は
val fibs = {
def go(f0: Int, f1: Int): Stream[Int] =
cons(f0, go(f1, f0+f1))
go(0, 1)
}
これを見て
def fibs2(n1:Int,n2:Int):Stream[Int]=cons(n1,fibs2(n2,n1+n2))
でもいいのではないかと思ったが。。。
2015年5月25日月曜日
scala関数型デザイン&プログラミング P88 89
Exercise 5.4 Streamの要素のうち、指定された述語とマッチするものをすべてチェックするforAllを実装せよ。
def forAll(p:A=>Boolean):Boolean =
foldRight(true)((a,b)=p(a)&&b)
Exercise 5.5 foldRightを使ってtakeWhileを実装せよ
def takeWhile3(p:A=>Boolean):Stream[A] =
foldRight(empty[A])((a,st)=>if p(a) cons(a,st) else st)
最後をstにしたが、解答はemptyだった。そうしないと、いったんfalseになっても、trueになると
前のStreamに追加されていく。(あとで出てくるfilterだとそれでいいが)
Exercise 5.6 foldRigthを使ってheadOptionを実装せよ
def headOption:Option[A] =
foldRight2(None:Option[A])( (a,_) =>if (a!=Nil) Some(a) else None )
最初foldRightの引数のNoneにOption[A]をつけなかったところ、エラーがでた。このへんの必要性について、いまいち理解できてない。
解答は
def headOption: Option[A] =
foldRight(None: Option[A])((h,_) => Some(h))
となっていた。わざわざifはつける必要がないといことだ。hがNilでもNoneとなるようだ。
Exercise 5.7 foldRightを使って、map,filter,append.flatMapを実装せよ
def map[B](f:A=>B):Stream[B] =
foldRight2(empty[B])( (a,st) => cons(f(a),st) )
def filter(f: A => Boolean): Stream[A] =
foldRight2(empty[B])( (a,st) => if (f(a)) cons(a,st) else st)
def append[A](as:Stream[A],bs:Stream[A]):Stream[A]=
as.foldRight2(bs)((a,b)=>cons(a,b))
def forAll(p:A=>Boolean):Boolean =
foldRight(true)((a,b)=p(a)&&b)
Exercise 5.5 foldRightを使ってtakeWhileを実装せよ
def takeWhile3(p:A=>Boolean):Stream[A] =
foldRight(empty[A])((a,st)=>if p(a) cons(a,st) else st)
最後をstにしたが、解答はemptyだった。そうしないと、いったんfalseになっても、trueになると
前のStreamに追加されていく。(あとで出てくるfilterだとそれでいいが)
Exercise 5.6 foldRigthを使ってheadOptionを実装せよ
def headOption:Option[A] =
foldRight2(None:Option[A])( (a,_) =>if (a!=Nil) Some(a) else None )
最初foldRightの引数のNoneにOption[A]をつけなかったところ、エラーがでた。このへんの必要性について、いまいち理解できてない。
解答は
def headOption: Option[A] =
foldRight(None: Option[A])((h,_) => Some(h))
となっていた。わざわざifはつける必要がないといことだ。hがNilでもNoneとなるようだ。
Exercise 5.7 foldRightを使って、map,filter,append.flatMapを実装せよ
def map[B](f:A=>B):Stream[B] =
foldRight2(empty[B])( (a,st) => cons(f(a),st) )
def filter(f: A => Boolean): Stream[A] =
foldRight2(empty[B])( (a,st) => if (f(a)) cons(a,st) else st)
def append[A](as:Stream[A],bs:Stream[A]):Stream[A]=
as.foldRight2(bs)((a,b)=>cons(a,b))
としたが、これでは引数を非正格にという条件にあわないので、間違い。
正しくは
def append[B>:A] (bs: => Stream[B]):Stream[B]=
foldRight2(bs)((a,b)=>cons(a,b))
ということだった。変位についても考慮して上位のBの型にしないとだめだそうだ。変位の指定ははまだ理解が難しい。
def flatMap[B](f:A=>Stream[B]):Stream[B] =
foldRight(empty[B])( (a,st)=>cons(f(a).head,st) )
foldRight(empty[B])( (a,st)=>cons(f(a).head,st) )
ということは無理だったheadのような使いかたはできない
正解は foldRight(empty[B])((a,st) => f(a).append(st))
appendを使うことは気づかなかった
2015年5月24日日曜日
scala関数型デザイン&プログラミング P86~87
Exercise5.2 Streamの先頭からn個の要素を取り出す関数take(n)とn個の要素をスキップするdrop(n)関数を実装せよ
def take(n:Int):Stream[A] = this match {
case Cons(x,xs) if n>1 => cons(x(),xs().take(n-1))
case Cons(x,_) if n==1 => cons(x(),empty)
case Empty => Stream()
}
これをprintln(Stream(1,2,3,4).take(2).toList)で確認してみた
def drop(n:Int):Stream[A]=this match {
case Cons(x,xs) if n>0 => xs().drop(n-1)
case Cons(x,xs) if n==0 => cons(x(),xs())
case Empty => Stream()
}
println(Stream(1,2,3,4).drop(3).toList)で確認したが、これだと、無駄があったようだ。
def drop2(n: Int): Stream[A] = this match {
case Cons(_, t) if n > 0 => t().drop(n - 1)
case _ => this
}
解答はこうなっていた。
Exercise5.3 Streamの先頭から指定された述語とマッチする要素をすべて取り出す takeWhile関数を記述せよ
def takeWhile(f: A => Boolean): Stream[A] = this match {
case Cons(h,t) if f(h()) => cons(h(), t() takeWhile f)
case _ => empty
}
これは、なぜかprintln(Stream(1,2,3,4).takeWhile2(_>2).toList)とするとList()と表示される。
よく考えたら、先頭から~マッチしないとだめなわけだから、_>2でなく_<3などで試せばいいわけだ。
def take(n:Int):Stream[A] = this match {
case Cons(x,xs) if n>1 => cons(x(),xs().take(n-1))
case Cons(x,_) if n==1 => cons(x(),empty)
case Empty => Stream()
}
これをprintln(Stream(1,2,3,4).take(2).toList)で確認してみた
def drop(n:Int):Stream[A]=this match {
case Cons(x,xs) if n>0 => xs().drop(n-1)
case Cons(x,xs) if n==0 => cons(x(),xs())
case Empty => Stream()
}
println(Stream(1,2,3,4).drop(3).toList)で確認したが、これだと、無駄があったようだ。
def drop2(n: Int): Stream[A] = this match {
case Cons(_, t) if n > 0 => t().drop(n - 1)
case _ => this
}
解答はこうなっていた。
Exercise5.3 Streamの先頭から指定された述語とマッチする要素をすべて取り出す takeWhile関数を記述せよ
def takeWhile(f: A => Boolean): Stream[A] = this match {
case Cons(h,t) if f(h()) => cons(h(), t() takeWhile f)
case _ => empty
}
これは、なぜかprintln(Stream(1,2,3,4).takeWhile2(_>2).toList)とするとList()と表示される。
よく考えたら、先頭から~マッチしないとだめなわけだから、_>2でなく_<3などで試せばいいわけだ。
scala関数型デザイン&プログラミング P86
Exercise 5.1 StreamをListに変換し、それによりストリームを強制的に評価する関数を記述せよ。
なぜか、REPLではうまくいかなかった。eclipseでこんな感じで確かめてみた。末尾再帰でないので、あまりよくないらしい。解答にはよりよい方法がのっていた。
import Stream._
case object Empty extends Stream[Nothing]
case class Cons[+A](h: () => A, t: () => Stream[A]) extends Stream[A]
object Main {
def main(args:Array[String]) = {
なぜか、REPLではうまくいかなかった。eclipseでこんな感じで確かめてみた。末尾再帰でないので、あまりよくないらしい。解答にはよりよい方法がのっていた。
import Stream._
case object Empty extends Stream[Nothing]
case class Cons[+A](h: () => A, t: () => Stream[A]) extends Stream[A]
object Main {
def main(args:Array[String]) = {
println(Stream(1,2,3).toList)
}
trait Stream[+A] {
def toList: List[A] = this match {
case Empty => List()
case Cons(h,t) => h() :: t().toList
}
}
object Stream {
def cons[A](hd: => A, tl: => Stream[A]): Stream[A] = {
lazy val head = hd
lazy val tail = tl
Cons(() => head, () => tail)
}
def empty[A]: Stream[A] = Empty
def apply[A](as: A*): Stream[A] =
if (as.isEmpty) empty
else cons(as.head, apply(as.tail: _*))
}
こちらが模範解答だが、なかなか思いつかないかも
def toList: List[A] = {
def go(s: Stream[A], acc: List[A]): List[A] = s match {
case Cons(h,t) => go(t(), h() :: acc)
case _ => acc
}
go(this, List()).reverse
}
こちらが模範解答だが、なかなか思いつかないかも
def toList: List[A] = {
def go(s: Stream[A], acc: List[A]): List[A] = s match {
case Cons(h,t) => go(t(), h() :: acc)
case _ => acc
}
go(this, List()).reverse
}
scala関数型デザイン&プログラミング P77
Exercise 4.7 Eitherでsequenceとtraverseを実装せよ
def sequence[E,A](es:List[Either[E,A]]):Either[E,List[A]]=
es match {
case Nil => Right(Nil)
case x::xs => x flatMap(xx => sequence(xs) map(xx::_) )
}
def traverse[E,A,B](as:List[A])(f:A=>Either[E,B]):Either[E,List[B]] =
as match {
case Nil => Right(Nil)
case h::t => f(h).map2(traverse(t)(f))(_::_)
}
としてみた。
解答には
def sequence_1[E,A](es: List[Either[E,A]]): Either[E,List[A]] =
traverse(es)(x => x)
のように、sequenceはtraverseを使う方法がでていた。
ただ、使い方がいまひとつわからなかった。
def sequence[E,A](es:List[Either[E,A]]):Either[E,List[A]]=
es match {
case Nil => Right(Nil)
case x::xs => x flatMap(xx => sequence(xs) map(xx::_) )
}
def traverse[E,A,B](as:List[A])(f:A=>Either[E,B]):Either[E,List[B]] =
as match {
case Nil => Right(Nil)
case h::t => f(h).map2(traverse(t)(f))(_::_)
}
としてみた。
解答には
def sequence_1[E,A](es: List[Either[E,A]]): Either[E,List[A]] =
traverse(es)(x => x)
のように、sequenceはtraverseを使う方法がでていた。
ただ、使い方がいまひとつわからなかった。
val ls=List(Right(1),Right(2))
val l=List(1,2)
val el=Right(List(3,4))
println(el.traverse(l)(i=>Right(i*2)))
println(el.sequence(ls))
println(el.sequence_1(ls))
のように、elをつけないと実行できない。実際にはlやlsしか使ってないのだが。。。基本的なことなんだろうが、勉強不足。
scala関数型デザイン&プログラミング P76
Exercise 4.6 Right値を操作するmap,flatMap,orElse,map2をEitherに追加せよ
map2については内包表記を使うと簡潔になる
import scala.{Option => _, Either => _, _}
object Main {
def main(args:Array[String]) = {
val x=Right(1)
val y=Left(22)
println( x.map(i=>i*2))
println(x.flatMap(i=>Right(i)))
println(x.orElse(Left(999)))
println(y.orElse(Left(999)))
println(x.map2(Right(2))((a,b)=>a+b))
}
}
sealed trait Either[+E,+A] {
def map[B](f:A=>B):Either[E,B] = this match {
case Left(e) => Left(e)
case Right(a) => Right(f(a))
}
def flatMap[EE>:E,B](f:A=>Either[EE,B]):Either[EE,B] = this match {
case Left(e) => Left(e)
case Right(a) => f(a)
}
def orElse[EE >: E, AA >: A](b: => Either[EE, AA]): Either[EE, AA] = this match {
case Left(e) => b
case a => a
}
def map2[EE>:E,B,C](b:Either[EE,B])(f:(A,B)=>C):Either[EE,C] =
for { a <- this; b1 <- b } yield f(a,b1)
}
case class Left[+E](get: E) extends Either[E,Nothing]
case class Right[+A](get: A) extends Either[Nothing,A]
map2については内包表記を使うと簡潔になる
import scala.{Option => _, Either => _, _}
object Main {
def main(args:Array[String]) = {
val x=Right(1)
val y=Left(22)
println( x.map(i=>i*2))
println(x.flatMap(i=>Right(i)))
println(x.orElse(Left(999)))
println(y.orElse(Left(999)))
println(x.map2(Right(2))((a,b)=>a+b))
}
}
sealed trait Either[+E,+A] {
def map[B](f:A=>B):Either[E,B] = this match {
case Left(e) => Left(e)
case Right(a) => Right(f(a))
}
def flatMap[EE>:E,B](f:A=>Either[EE,B]):Either[EE,B] = this match {
case Left(e) => Left(e)
case Right(a) => f(a)
}
def orElse[EE >: E, AA >: A](b: => Either[EE, AA]): Either[EE, AA] = this match {
case Left(e) => b
case a => a
}
def map2[EE>:E,B,C](b:Either[EE,B])(f:(A,B)=>C):Either[EE,C] =
for { a <- this; b1 <- b } yield f(a,b1)
}
case class Left[+E](get: E) extends Either[E,Nothing]
case class Right[+A](get: A) extends Either[Nothing,A]
2015年5月23日土曜日
scala関数型デザイン&プログラミング P73
Exercise4.5 traverse関数を実装せよ。リストを1回だけ調べる効率よい実装にすること。traverseの観点からsequenceを実装するとよい。
f(x):Option[B]だし、traverse()():Option[List[B]]なので
x::xsから 最終的に map2(f(x),traverse(xs)(f))(_::_) にすればよさそうな気がしてた。
が、foldMapの使用も考えたりするうち、よくわからなくなり、正解を見た。
def traverse[A, B](a: List[A])(f: A => Option[B]): Option[List[B]] =
a match {
case Nil => Some(Nil)
case h::t => map2(f(h), traverse(t)(f))(_ :: _)
}
別解は
def traverse_1[A,B](a:List[A])(f:A=>Option[B]):Option[List[B]] =
a.foldRight[Option[List[B]] ](Some(Nil))( (x,y) => map2(f(x),y)(_::_) )
f(x):Option[B]だし、traverse()():Option[List[B]]なので
x::xsから 最終的に map2(f(x),traverse(xs)(f))(_::_) にすればよさそうな気がしてた。
が、foldMapの使用も考えたりするうち、よくわからなくなり、正解を見た。
def traverse[A, B](a: List[A])(f: A => Option[B]): Option[List[B]] =
a match {
case Nil => Some(Nil)
case h::t => map2(f(h), traverse(t)(f))(_ :: _)
}
別解は
def traverse_1[A,B](a:List[A])(f:A=>Option[B]):Option[List[B]] =
a.foldRight[Option[List[B]] ](Some(Nil))( (x,y) => map2(f(x),y)(_::_) )
scala関数型デザイン&プログラミング Exercise 4.4
Exercise 4.4 OptionのリストをひとつのOptionにまとめるsequence関数を実装せよ。
def sequence[A](a:List[Option[A]]) :Option[List[A]] =
a match {
case Nil=>Some(Nil)
case Some(x)::xs => Some( x::sequence(xs) )
}
と思ったが、sequence(xs)はList[A]でないから、当然エラーが発生する。Optionを取り除くという発想ではだめということがわかる。やはり、これまで通り、flatMapやmapを駆使するとうまくいくようだ。
正解は
def sequence[A](a:List[Option[A]]) :Option[List[A]] =
a match {
case Nil=>Some(Nil)
case x::xs => x flatMap( xx => sequence(xs) map(xx::_) )
}
aはOption[A]のリストで、先頭をx、残りがxsとすると
xをflatMapに適用(関数は xx => sequence(xs) map(xx::_) )
ここで、sequence(xs) map(xx::_) がなかなか発想できなかった。
Optin[List[A]]でなければならないので、Some(xx::(xsのOptionがとれたリスト))となるようにする必要がある
map((xsのOptionがとれたリスト)=>xx::(xsのOptionがとれたリスト))となるようにして、このmapは、何に適用なるかというと
sequence(xs)、つまり(xsのOptionがとれたリスト)のOptionということになる。
別解として、
def sequence_1[A](a: List[Option[A]]): Option[List[A]] =
a.foldRight[Option[List[A]]](Some(Nil))( (x,y) => map2(x,y)(_ :: _) )
ここで、理由はまだよく理解してないが、[Option[List[A]]]がないとエラーになるようだ。
def sequence[A](a:List[Option[A]]) :Option[List[A]] =
a match {
case Nil=>Some(Nil)
case Some(x)::xs => Some( x::sequence(xs) )
}
と思ったが、sequence(xs)はList[A]でないから、当然エラーが発生する。Optionを取り除くという発想ではだめということがわかる。やはり、これまで通り、flatMapやmapを駆使するとうまくいくようだ。
正解は
def sequence[A](a:List[Option[A]]) :Option[List[A]] =
a match {
case Nil=>Some(Nil)
case x::xs => x flatMap( xx => sequence(xs) map(xx::_) )
}
aはOption[A]のリストで、先頭をx、残りがxsとすると
xをflatMapに適用(関数は xx => sequence(xs) map(xx::_) )
ここで、sequence(xs) map(xx::_) がなかなか発想できなかった。
Optin[List[A]]でなければならないので、Some(xx::(xsのOptionがとれたリスト))となるようにする必要がある
map((xsのOptionがとれたリスト)=>xx::(xsのOptionがとれたリスト))となるようにして、このmapは、何に適用なるかというと
sequence(xs)、つまり(xsのOptionがとれたリスト)のOptionということになる。
別解として、
def sequence_1[A](a: List[Option[A]]): Option[List[A]] =
a.foldRight[Option[List[A]]](Some(Nil))( (x,y) => map2(x,y)(_ :: _) )
ここで、理由はまだよく理解してないが、[Option[List[A]]]がないとエラーになるようだ。
scala関数型デザイン&プログラミング Exercise 4.3
Exercise 4.32項関数を使いOption型の2つの値を結合する総称関数map2を実装せよ
def map2[A,B,C](a:Option[A],b:Option[B])(f:(A,B)=>C):Option[C] =
(a,b) match {
case (Some(aa),Some(bb)) => Some(f(aa,bb))
case (_,_) =>None
}
と考えたが、Optionは原則flatMapを使ったほうがスマートになるらしい。解答は
def map2a[A,B,C](a: Option[A], b: Option[B])(f: (A, B) => C): Option[C] =
a flatMap (aa => b map (bb => f(aa, bb)))
def lift[A,B](f:A=>B):Option[A]=>Option[B]=_ map f
を参考にすると
b map (bb => f(aa,bb))がいわゆるliftを適用したものにあたり bb=>f(aa,bb)がA=>Bにあたる。
Option[B]=>Option[C]という関数にbを適用した結果だから、b map (bb => f(aa,bb)):Option[C]とみなせる。
(ただ、この部分でaaが確定してないから、aaの関数ともみなせる?)
したがって、aa:AからOption[C]への関数がflatMapの引数となっており、
a:Option[A]をmap2aに適用すれば、Option[C]に変換される。
二項関数は、flatMapとmapをうまく組み合わせるとできるということは、わかったが、けっこう、ややこしい。
def map2[A,B,C](a:Option[A],b:Option[B])(f:(A,B)=>C):Option[C] =
(a,b) match {
case (Some(aa),Some(bb)) => Some(f(aa,bb))
case (_,_) =>None
}
と考えたが、Optionは原則flatMapを使ったほうがスマートになるらしい。解答は
def map2a[A,B,C](a: Option[A], b: Option[B])(f: (A, B) => C): Option[C] =
a flatMap (aa => b map (bb => f(aa, bb)))
def lift[A,B](f:A=>B):Option[A]=>Option[B]=_ map f
を参考にすると
b map (bb => f(aa,bb))がいわゆるliftを適用したものにあたり bb=>f(aa,bb)がA=>Bにあたる。
Option[B]=>Option[C]という関数にbを適用した結果だから、b map (bb => f(aa,bb)):Option[C]とみなせる。
(ただ、この部分でaaが確定してないから、aaの関数ともみなせる?)
したがって、aa:AからOption[C]への関数がflatMapの引数となっており、
a:Option[A]をmap2aに適用すれば、Option[C]に変換される。
二項関数は、flatMapとmapをうまく組み合わせるとできるということは、わかったが、けっこう、ややこしい。
2015年5月21日木曜日
scala関数型デザイン&プログラミング P68
Exercise 4.2 flatMapをベースにしてvariance関数を実装せよ。math.pow(x-m,2)の平均が分散
def mean(xs:Seq[Double]):Option[Double]=
if (xs.isEmpty) None
else Some(xs.sum/xs.length)
を使うようだ。
meanのことを忘れていたし、まったく思いつかなかったので、正解を見たら
def variance(xs:Seq[Double]):Option[Double]=
mean(xs).flatMap(m=>mean(xs.map( x=>math.pow(x-m,2))))
mean(xs).flatMap(m=>mean(map(xs)(x=>math.pow(x-m,2))))
とすると、うまくいかなかった。Listのmapの仕様とはちがっている?ようだ。
def mean(xs:Seq[Double]):Option[Double]=
if (xs.isEmpty) None
else Some(xs.sum/xs.length)
を使うようだ。
meanのことを忘れていたし、まったく思いつかなかったので、正解を見たら
def variance(xs:Seq[Double]):Option[Double]=
mean(xs).flatMap(m=>mean(xs.map( x=>math.pow(x-m,2))))
となっている。たったこれだけの文字数ですむとは驚きだ。ためしに
def variance(xs:Seq[Double]):Option[Double]=mean(xs).flatMap(m=>mean(map(xs)(x=>math.pow(x-m,2))))
とすると、うまくいかなかった。Listのmapの仕様とはちがっている?ようだ。
scala関数型デザイン&プログラミング P67
Exercise4.1 trait Optionのmap,flatMap,getOeElse,getElse,filterの関数をOptionで実装せよ。
eclipseでコンパイルしないとうまく実行できなかった。
とりあえず、解答も参考にしながら、次のようなものを考えてみた。
import scala.{Option => _, Either => _, _}
//以下のprintln文で動作を確認してみた
object Main {
def main(args:Array[String]) = {
val x:Option[Int]=Some(1)
val y:Option[String]=None
println(x)
println(x.map(i=>i.toDouble))
println(y.getOrElse(999))
println(x.flatMap(i=>Some(i.toDouble)))
println(x.filter(_<2))
}
}
case class Some[+A](get: A) extends Option[A]
case object None extends Option[Nothing]
sealed trait Option[+A] {
def map[B](f: A => B): Option[B] = this match {
case None => None
case Some(a) => Some(f(a))
}
//Option値がNoneなら、ディフォルト値だが、Someならその中身
// 引数名: =>引数の型 は、遅延評価(メソッド呼び出す前には評価されない)
def getOrElse[B>:A](default: => B): B = this match {
case None => default
case Some(a) => a
}
def flatMap[B](f: A => Option[B]): Option[B] =
map(f).getOrElse(None)
//二つ目のOptionというのが意味が分からなかったが、要するに引数のことでしょうか?
//orElse(一つ目のOption,二つ目のOption)とみなしたということ? 一つ目のOption.orElse(二つ目のOption)と考えていたのでよくわからなかった。
//自分自身はthisとするようだ
def orElse[B>:A](ob: => Option[B]): Option[B] = this match {
case None=> ob
case Some(b) => this
}
// 解答の
// def orElse[B>:A](ob: => Option[B]): Option[B] =
// this map (Some(_)) getOrElse ob
// という発想はなかなか出てこなかった。Some(_)は、b:B=>Some(b):Option[B] そして
//map(b=>Some(b)でSome(Some(b))になるが
//getOrElseでまた、Some(b)にもどるということだろうか。ちょっと回りくどい気がしないでもないが。
def filter(f: A => Boolean): Option[A] = this match {
case None => None
case Some(a) => if (f(a)) this else None
}
}
eclipseでコンパイルしないとうまく実行できなかった。
とりあえず、解答も参考にしながら、次のようなものを考えてみた。
import scala.{Option => _, Either => _, _}
//以下のprintln文で動作を確認してみた
object Main {
def main(args:Array[String]) = {
val x:Option[Int]=Some(1)
val y:Option[String]=None
println(x)
println(x.map(i=>i.toDouble))
println(y.getOrElse(999))
println(x.flatMap(i=>Some(i.toDouble)))
println(x.filter(_<2))
}
}
case class Some[+A](get: A) extends Option[A]
case object None extends Option[Nothing]
sealed trait Option[+A] {
def map[B](f: A => B): Option[B] = this match {
case None => None
case Some(a) => Some(f(a))
}
//Option値がNoneなら、ディフォルト値だが、Someならその中身
// 引数名: =>引数の型 は、遅延評価(メソッド呼び出す前には評価されない)
def getOrElse[B>:A](default: => B): B = this match {
case None => default
case Some(a) => a
}
def flatMap[B](f: A => Option[B]): Option[B] =
map(f).getOrElse(None)
//二つ目のOptionというのが意味が分からなかったが、要するに引数のことでしょうか?
//orElse(一つ目のOption,二つ目のOption)とみなしたということ? 一つ目のOption.orElse(二つ目のOption)と考えていたのでよくわからなかった。
//自分自身はthisとするようだ
def orElse[B>:A](ob: => Option[B]): Option[B] = this match {
case None=> ob
case Some(b) => this
}
// 解答の
// def orElse[B>:A](ob: => Option[B]): Option[B] =
// this map (Some(_)) getOrElse ob
// という発想はなかなか出てこなかった。Some(_)は、b:B=>Some(b):Option[B] そして
//map(b=>Some(b)でSome(Some(b))になるが
//getOrElseでまた、Some(b)にもどるということだろうか。ちょっと回りくどい気がしないでもないが。
def filter(f: A => Boolean): Option[A] = this match {
case None => None
case Some(a) => if (f(a)) this else None
}
}
2015年5月17日日曜日
scala関数型デザイン&プログラミング P57
Exercise 3.29 size,maximum,depth,mapを一般化し、それらの類似点を抽象化する新しいfold関数を記述せよ。
def fold[A,B](t:Tree[A])(lf:A=>B,bf:(B,B)=>B):B=
t match {
case Leaf(a) =>lf(a)
case Branch(lt,rt)=>bf(fold(lt)(lf,bf),fold(rt)(lf,bf))
}
size,maximum,depth,mapの類似点は、
1)t:Tree[A]が引数で、match式で使われていること
2)case Leaf(a)の右側がaの関数と考えられる
このaの関数lfがいろいろ変えることで、一般化できる。このlfをfoldの引数にしてやるとよい。
3)case Branch(lt,rt)の右側がlt,rtを引数とした再帰関数の関数と考えられる
このlt,rtを引数とした再帰関数は、どれにも共通しているので、これらfold(lt)(lf,bf)とfold(rt)(lf,bf)を引数としたbfという関数をいろいろ変えることで、一般化できる。それで、このbfもfoldの引数にする。
関数を引数にできると、プログラムの抽象化の幅も広がるということがこの練習問題からよくわかります。
def fold[A,B](t:Tree[A])(lf:A=>B,bf:(B,B)=>B):B=
t match {
case Leaf(a) =>lf(a)
case Branch(lt,rt)=>bf(fold(lt)(lf,bf),fold(rt)(lf,bf))
}
size,maximum,depth,mapの類似点は、
1)t:Tree[A]が引数で、match式で使われていること
2)case Leaf(a)の右側がaの関数と考えられる
このaの関数lfがいろいろ変えることで、一般化できる。このlfをfoldの引数にしてやるとよい。
3)case Branch(lt,rt)の右側がlt,rtを引数とした再帰関数の関数と考えられる
このlt,rtを引数とした再帰関数は、どれにも共通しているので、これらfold(lt)(lf,bf)とfold(rt)(lf,bf)を引数としたbfという関数をいろいろ変えることで、一般化できる。それで、このbfもfoldの引数にする。
関数を引数にできると、プログラムの抽象化の幅も広がるということがこの練習問題からよくわかります。
scala関数型デザイン&プログラミング P56
Exercise 3.25 LeafとBranchの数を数えるsize関数を記述せよ
def size[A](t:Tree[A]):Int=
t match {
case Leaf(a) => 1
case Branch(lt,rt) => 1+size(lt)+size(rt)
}
Exercise 3.26 Tree[Int]の最大の要素を]返すmaximum関数を記述せよ。
def maximum(t:Tree[Int]):Int=
t match {
case Leaf(a) =>a
case Branch(lt,rt) => maximum(lt) max maximum(rt)
}
Exercise 3.27 2分木のルートから任意のLeafまでの最長パスを返すdepth関数を記述せよ
def depth[A](t:Tree[A]):Int=
t match {
case Leaf(_) => 0
case Branch(lt,rt) => 1+(depth(lt) max depth(rt))
}
Exercise 3.28 2分木の各要素を特定の関数を使って変換するmap関数を記述せよ。
def map[A,B](t:Tree[A])(f:A=>B):Tree[B]=
t match {
case Leaf(a)=>Leaf(f(a))
case Branch(lt,rt)=>Branch(map(lt)(f),map(rt)(f))
}
def size[A](t:Tree[A]):Int=
t match {
case Leaf(a) => 1
case Branch(lt,rt) => 1+size(lt)+size(rt)
}
Exercise 3.26 Tree[Int]の最大の要素を]返すmaximum関数を記述せよ。
def maximum(t:Tree[Int]):Int=
t match {
case Leaf(a) =>a
case Branch(lt,rt) => maximum(lt) max maximum(rt)
}
Exercise 3.27 2分木のルートから任意のLeafまでの最長パスを返すdepth関数を記述せよ
def depth[A](t:Tree[A]):Int=
t match {
case Leaf(_) => 0
case Branch(lt,rt) => 1+(depth(lt) max depth(rt))
}
Exercise 3.28 2分木の各要素を特定の関数を使って変換するmap関数を記述せよ。
def map[A,B](t:Tree[A])(f:A=>B):Tree[B]=
t match {
case Leaf(a)=>Leaf(f(a))
case Branch(lt,rt)=>Branch(map(lt)(f),map(rt)(f))
}
scala関数デザイン&プログラミング P54
Exercise 3.24 Listに別のListがサブシーケンスとして含まれるかどうか調べるhasSubsequenceを実装せよ
def hasSubsequence[A](sup:List[A],sub:List[A]):Boolean =
(sup,sub) match {
case (Nil,_) => false
case (_,Nil) => true
case (Cons(x,xs),Cons(y,ys)) => if (x==y) hasSubsequence(xs,ys) else hasSubsequence(xs,sub)
}
としてみたが、間違いに気づいた。最初に、 case (_,Nil) => trueをもってこないと、うまくいかない。
def hasSubsequence[A](sup:List[A],sub:List[A]):Boolean =
(sup,sub) match {
case (_,Nil) => true
case (Nil,_) => false
case (Cons(x,xs),Cons(y,ys)) => if (x==y) hasSubsequence(xs,ys) else hasSubsequence(xs,sub)
}
これでも、まだ完全ではない。途中までx==yだと、ysに半端なListが行くため、もともとのsubにリセットされない。
そこで、次のようにしてみた。
def hasSubsequence[A](sup:List[A],sub:List[A]):Boolean =
{
def icchi(supx:List[A],subx:List[A]):Boolean =
(supx,subx) match {
case (_,Nil) => true
case (Nil,_) => false
case (Cons(x,xs),Cons(y,ys)) => if (x==y) icchi(xs,ys) else icchi(xs,sub)
}
icchi(sup,sub)
}
あまりすっきりした形ではないが、これでどうだろうか?意外に難しい。
scala関数デザイン&プログラミング P53
Exercise3.20 mapと同じ働きをするflatMap関数を記述せよ。
def flatMap[A,B](as:List[A])(f:A=>List[B]):List[B] =
foldRight(as:List[A],Nil:List[B])( (x,bs)=>concat(List(f(x),bs)) )
もっと簡単に
def flatMap[A,B](l: List[A])(f: A => List[B]): List[B] =
concat(map(l)(f))
でいいようだ。map(l)(f)はList(List[B])の型になるが、concatによりList[B]になるということのようだ。
Exercise3.21 flatMapを使ってfilterを実装せよ。
def filter2[A](as:List[A])(f:A=>Boolean):List[A]=
flatMap(as)((i)=> if (f(i)) List(i) else List() )
Exercise3.22 リスト2つをうけとり、対応する要素どうしを足し合わせて新しいリストを生成する関数を記述せよ
def plus(as:List[Int],bs:List[Int]):List[Int]=
(as,bs) match {
case (Nil,Nil)=>Nil
case (Cons(x,xs),Nil)=>Cons(x,plus(xs,Nil))
case (Nil,Cons(y,ys))=>Cons(y,plus(Nil,ys))
case (Cons(x,xs),Cons(y,ys)) => Cons(x+y,plus(xs,ys))
}
解答は、どちらも数字がないと足さないとしていたが、ここでは、数字がないときは、0とみなしていちおう計算してみた。
Exercise3.23 3.22で作成した関数を、整数または加算に限定されないように一般化せよ
def zipWith[A](as:List[A],bs:List[A])(f:(A,A)=>A):List[A]=
(as,bs) match {
case (_,Nil)=>Nil
case (Nil,_)=>Nil
case (Cons(x,xs),Cons(y,ys)) => Cons(f(x,y),zipWith(xs,ys)(f))
}
正解では、すべての型をAにしていなかった。f:(A,B)=>Cと直す必要あり。
def flatMap[A,B](as:List[A])(f:A=>List[B]):List[B] =
foldRight(as:List[A],Nil:List[B])( (x,bs)=>concat(List(f(x),bs)) )
もっと簡単に
def flatMap[A,B](l: List[A])(f: A => List[B]): List[B] =
concat(map(l)(f))
でいいようだ。map(l)(f)はList(List[B])の型になるが、concatによりList[B]になるということのようだ。
Exercise3.21 flatMapを使ってfilterを実装せよ。
def filter2[A](as:List[A])(f:A=>Boolean):List[A]=
flatMap(as)((i)=> if (f(i)) List(i) else List() )
Exercise3.22 リスト2つをうけとり、対応する要素どうしを足し合わせて新しいリストを生成する関数を記述せよ
def plus(as:List[Int],bs:List[Int]):List[Int]=
(as,bs) match {
case (Nil,Nil)=>Nil
case (Cons(x,xs),Nil)=>Cons(x,plus(xs,Nil))
case (Nil,Cons(y,ys))=>Cons(y,plus(Nil,ys))
case (Cons(x,xs),Cons(y,ys)) => Cons(x+y,plus(xs,ys))
}
解答は、どちらも数字がないと足さないとしていたが、ここでは、数字がないときは、0とみなしていちおう計算してみた。
Exercise3.23 3.22で作成した関数を、整数または加算に限定されないように一般化せよ
def zipWith[A](as:List[A],bs:List[A])(f:(A,A)=>A):List[A]=
(as,bs) match {
case (_,Nil)=>Nil
case (Nil,_)=>Nil
case (Cons(x,xs),Cons(y,ys)) => Cons(f(x,y),zipWith(xs,ys)(f))
}
正解では、すべての型をAにしていなかった。f:(A,B)=>Cと直す必要あり。
scala関数デザイン&プログラミング P52
Exercise 3.16 各要素に1ずつたして整数のリストを返す関数を記述せよ
def add1(as:List[Int]):List[Int]=
as match {
case Nil => Nil
case Cons(x,xs)=> Cons(x+1,add1(xs))
}
def add1f(as:List[Int]):List[Int]=
foldRight(as:List[Int],Nil:List[Int])((a:Int,b:List[Int])=>Cons(a+1,b))
Exercise 3.17 List[Double]の各値をStringに変換する関数を記述せよ
def toStringD(as:List[Double]):List[String]=
foldRight(as:List[Double],Nil:List[String])((a:Double,b:List[String])=>Cons(a.toString,b))
Exercise 3.18 リストの各要素を変更し、かつリストの構造をそのまま保つ総称関数mapを記述せよ。
def map[A,B}(as:List[A])(f:A=>B):List[B]=
foldRight(as:List[A],Nil:List[B])((a:A,b:List[B])=>Cons(f(a),b))
Exercise 3.19 与えられた述語条件が満たされるまでリストから要素を削除するfilter関数を記述せよ。
def filter[A](as:List[A])(f:A=>Boolean):List[A]=
foldRight(as:List[A],Nil:List[A])((a:A,b:List[A])=>(if (f(a)) Cons(a,b) else b ))
def add1(as:List[Int]):List[Int]=
as match {
case Nil => Nil
case Cons(x,xs)=> Cons(x+1,add1(xs))
}
def add1f(as:List[Int]):List[Int]=
foldRight(as:List[Int],Nil:List[Int])((a:Int,b:List[Int])=>Cons(a+1,b))
Exercise 3.17 List[Double]の各値をStringに変換する関数を記述せよ
def toStringD(as:List[Double]):List[String]=
foldRight(as:List[Double],Nil:List[String])((a:Double,b:List[String])=>Cons(a.toString,b))
Exercise 3.18 リストの各要素を変更し、かつリストの構造をそのまま保つ総称関数mapを記述せよ。
def map[A,B}(as:List[A])(f:A=>B):List[B]=
foldRight(as:List[A],Nil:List[B])((a:A,b:List[B])=>Cons(f(a),b))
Exercise 3.19 与えられた述語条件が満たされるまでリストから要素を削除するfilter関数を記述せよ。
def filter[A](as:List[A])(f:A=>Boolean):List[A]=
foldRight(as:List[A],Nil:List[A])((a:A,b:List[A])=>(if (f(a)) Cons(a,b) else b ))
scala関数型デザイン&プログラミング P51-2
Exercise 3.14 foledLeftまたはfoldRightをベースとしてappendを実装せよ。
def append[A](as:List[A],bs:List[A]):List[A]=
foldLeft(reverse(as):List[A],bs:List[A])((b:List[A],a:A)=>Cons(a,b))
def append2[A](as:List[A],bs:List[A]):List[A]=
foldRight(as:List[A],bs:List[A])((a:A,b:List[A])=>Cons(a,b))
Exercise 3.15 複数のリストからなるリストを一つのリストとして連結する関数を記述せよ。
実行時間についてはよくわからないが、これでどうか?
def renketu[A](as:List[List[A]]):List[A]=
foldRight(as:List[List[A]],Nil:List[A])((a:List[A],b:List[A])=>append(a,b))
def append[A](as:List[A],bs:List[A]):List[A]=
foldLeft(reverse(as):List[A],bs:List[A])((b:List[A],a:A)=>Cons(a,b))
def append2[A](as:List[A],bs:List[A]):List[A]=
foldRight(as:List[A],bs:List[A])((a:A,b:List[A])=>Cons(a,b))
foldRightのほうは、reverseが不要なのでシンプル
Exercise 3.15 複数のリストからなるリストを一つのリストとして連結する関数を記述せよ。
実行時間についてはよくわからないが、これでどうか?
def renketu[A](as:List[List[A]]):List[A]=
foldRight(as:List[List[A]],Nil:List[A])((a:List[A],b:List[A])=>append(a,b))
2015年5月16日土曜日
scala関数型デザイン&プログラミング P51
Exercise3.11 foldLeftを使ってsum,product、リストの長さを計算する関数を記述せよ
def sum2(as:List[Int]):Int=
foldLeft(as,0)(_+_)
def product2(as:List[Int]):Int=
foldLeft(as,1)(_*_)
def length2[A](as:List[A]):Int=
foldLeft(as,0)((b,_)=>b+1)
Exercise3.12 要素が逆に並んだリストを返す関数を記述せよ。
def rev[A](as:List[A]):List[A]=
foldLeft(as,Nil:List[A])((b,a)=>Cons(a,b))
Exercise3.13 foldRigtからfoldLeftをつくる
def foldLeft2[A,B](as:List[A],z:B)(f:(B,A)=>B):B=
{
def g(a:A,b:B) :B = f(b,a)
foldRight(as,z)(g)
}
foldLeftからfoldRightをつくる
def foldRight2[A,B](as:List[A],z:B)(f:(A,B)=>B):B=
{
def g(b:B,a:A) :B = f(a,b)
foldLeft(as,z)(g)
}
としてみたが、そう簡単ではなかった。
3.13のfoldLeft2の正解は、
def foldLeftViaFoldRight[A,B](l: List[A], z: B)(f: (B,A) => B): B =
foldRight(l, (b:B) => b)((a,g) => b => g(f(b,a)))(z)
なのだが、これを見ても、すぐには理解できない。
foldRightの第一引数の型、List[A]でいいが、第二引数の型が、BのかわりにB=>B、つまり値ではなく、関数(b:B)=>bとするという考え方が、なかなか思いつかないところ。確かに、よく考えれば、型Bといえば、値であろうと関数であろうと論理的に問題はないことになる。
したがって、次の引数である(A,B)=>BのBのところが、関数B=>Bに変わるので、(A,B=>B)=>(B=>B)となる。これは、(a,g) =>( b=>g(f(b,a)) )の部分で、gもB=>Bという型だし、b=>g(f(b,a))もB=>Bという型になっているから、これも問題ない。
このB=>Bという関数が、foldRightで適用されたものは、foldRight(l, (b:B) => b)((a,g) => b => g(f(b,a)))であるが、これは、Bという型でなく、最終的にB=>Bの関数になるので、これだけでは、値が出てこない。そこで、この最終的にできた関数にzを引数としてやると
foldRight(l, (b:B) => b)((a,g) => b => g(f(b,a)))(z) となるようだ。
def foldRight(x:xs,z)(f)はf(x,foldRight(xs,z)(f))となっているが、このzの部分がdelay関数と呼ばれている?もののようだ。再帰を繰り返すことで、delay関数にxが適用なっていき、蓄積していくイメージだろうか。これをもとにして、次のようになる。
foldRight(1:List(2,3),b=>b)(f)=f(1,foldRight(List(2,3),b=>b)(f))=f(1,f(2,foldRight(List(3),b=>b)(f)))
=f(1,f(2,f(3,b=>b)))
ここで、fは(a,g)=>(b=>g(f(b,a))) より f(3,b=>b)=(Ident(f(b,3))
同様に fは(a,g)=>(b=>g(f(b,a))) より f(2,(f3,b=>b))=f(2,Ident(f(b,3)))=Ident(f(f(b,2),3))
これを繰り返し f(1,(f(2,f(3,b=>b)))=Ident(f(f(f(b,1),2),3)))
def sum2(as:List[Int]):Int=
foldLeft(as,0)(_+_)
def product2(as:List[Int]):Int=
foldLeft(as,1)(_*_)
def length2[A](as:List[A]):Int=
foldLeft(as,0)((b,_)=>b+1)
Exercise3.12 要素が逆に並んだリストを返す関数を記述せよ。
def rev[A](as:List[A]):List[A]=
foldLeft(as,Nil:List[A])((b,a)=>Cons(a,b))
Exercise3.13 foldRigtからfoldLeftをつくる
def foldLeft2[A,B](as:List[A],z:B)(f:(B,A)=>B):B=
{
def g(a:A,b:B) :B = f(b,a)
foldRight(as,z)(g)
}
foldLeftからfoldRightをつくる
def foldRight2[A,B](as:List[A],z:B)(f:(A,B)=>B):B=
{
def g(b:B,a:A) :B = f(a,b)
foldLeft(as,z)(g)
}
としてみたが、そう簡単ではなかった。
3.13のfoldLeft2の正解は、
def foldLeftViaFoldRight[A,B](l: List[A], z: B)(f: (B,A) => B): B =
foldRight(l, (b:B) => b)((a,g) => b => g(f(b,a)))(z)
なのだが、これを見ても、すぐには理解できない。
foldRightの第一引数の型、List[A]でいいが、第二引数の型が、BのかわりにB=>B、つまり値ではなく、関数(b:B)=>bとするという考え方が、なかなか思いつかないところ。確かに、よく考えれば、型Bといえば、値であろうと関数であろうと論理的に問題はないことになる。
したがって、次の引数である(A,B)=>BのBのところが、関数B=>Bに変わるので、(A,B=>B)=>(B=>B)となる。これは、(a,g) =>( b=>g(f(b,a)) )の部分で、gもB=>Bという型だし、b=>g(f(b,a))もB=>Bという型になっているから、これも問題ない。
このB=>Bという関数が、foldRightで適用されたものは、foldRight(l, (b:B) => b)((a,g) => b => g(f(b,a)))であるが、これは、Bという型でなく、最終的にB=>Bの関数になるので、これだけでは、値が出てこない。そこで、この最終的にできた関数にzを引数としてやると
foldRight(l, (b:B) => b)((a,g) => b => g(f(b,a)))(z) となるようだ。
def foldRight(x:xs,z)(f)はf(x,foldRight(xs,z)(f))となっているが、このzの部分がdelay関数と呼ばれている?もののようだ。再帰を繰り返すことで、delay関数にxが適用なっていき、蓄積していくイメージだろうか。これをもとにして、次のようになる。
foldRight(1:List(2,3),b=>b)(f)=f(1,foldRight(List(2,3),b=>b)(f))=f(1,f(2,foldRight(List(3),b=>b)(f)))
=f(1,f(2,f(3,b=>b)))
ここで、fは(a,g)=>(b=>g(f(b,a))) より f(3,b=>b)=(Ident(f(b,3))
同様に fは(a,g)=>(b=>g(f(b,a))) より f(2,(f3,b=>b))=f(2,Ident(f(b,3)))=Ident(f(f(b,2),3))
これを繰り返し f(1,(f(2,f(3,b=>b)))=Ident(f(f(f(b,1),2),3)))
scala関数型デザイン&プログラミング P50
Exercise3.9 foldRightを使ってリストの長さを計算せよ
def length[A](as:List[A]):Int=
foldRight(as,0)((a,b)=>b+1)
Exercise3.10 リスト再帰の総称関数foldLeftを記述せよ。
def foldLeft[A,B](as:List[A],z:B)(f:(B,A)=>B):B =
as match {
case Nil => z
case Cons(x, xs) => f(foldLeft(xs, z)(f),x)
}
これで、求められるけれど、末尾再帰でないので、だめなようだ。
あくまで、最後はfoldLeftの形でないとだめなので、正しい答は
def foldLeft[A,B](l: List[A], z: B)(f: (B, A) => B): B = l match {
case Nil => z
case Cons(x,xs) => foldLeft(xs, f(z,x))(f)
}
def length[A](as:List[A]):Int=
foldRight(as,0)((a,b)=>b+1)
Exercise3.10 リスト再帰の総称関数foldLeftを記述せよ。
def foldLeft[A,B](as:List[A],z:B)(f:(B,A)=>B):B =
as match {
case Nil => z
case Cons(x, xs) => f(foldLeft(xs, z)(f),x)
}
これで、求められるけれど、末尾再帰でないので、だめなようだ。
あくまで、最後はfoldLeftの形でないとだめなので、正しい答は
def foldLeft[A,B](l: List[A], z: B)(f: (B, A) => B): B = l match {
case Nil => z
case Cons(x,xs) => foldLeft(xs, f(z,x))(f)
}
2015年5月14日木曜日
scala関数型デザイン&プログラミング P45
Exercise 3.4 tailを一般化して、リストの先頭からn個の要素を削除するdropという関数に書き換えよ。
def drop[A](l:List[A],n:Int):List[A] =
l match {
case Nil=>Nil
case Cons(x,xs)=>if (n>1) drop(xs,n-1)
else xs
}
Exercise 3.5 述語とマッチする場合に限り、Listからその要素までの要素を削除するdropWhileを実装せよ。
def dropWhile[A](l:List[A],f:A=>Boolean):List[A] =
l match {
case Nil=>Nil
case Cons(x,xs)=>if (f(x)) dropWhile(xs,f)
else l
}
としてみたが、どうだろうか。
def drop[A](l:List[A],n:Int):List[A] =
l match {
case Nil=>Nil
case Cons(x,xs)=>if (n>1) drop(xs,n-1)
else xs
}
Exercise 3.5 述語とマッチする場合に限り、Listからその要素までの要素を削除するdropWhileを実装せよ。
def dropWhile[A](l:List[A],f:A=>Boolean):List[A] =
l match {
case Nil=>Nil
case Cons(x,xs)=>if (f(x)) dropWhile(xs,f)
else l
}
としてみたが、どうだろうか。
2015年5月13日水曜日
scala関数型デザイン&プログラミング P44
Exercise3.2
Listの最初の要素を削除する関数tailを実装せよ。
def tail[A](as:List[A]):List[A]=
as match {
case Nil => Nil
case Cons(x,xs)=>xs
}
Exercise3.3
最初の要素を別の値と置き換えるsetHead関数を実装せよ。
def setHead[A] (as:List[A] , y:A ) : List[A] =
as match {
case Nil =>Nil
case Cons(x,xs)=>Cons(y,xs)
}
Listの最初の要素を削除する関数tailを実装せよ。
def tail[A](as:List[A]):List[A]=
as match {
case Nil => Nil
case Cons(x,xs)=>xs
}
Exercise3.3
最初の要素を別の値と置き換えるsetHead関数を実装せよ。
def setHead[A] (as:List[A] , y:A ) : List[A] =
as match {
case Nil =>Nil
case Cons(x,xs)=>Cons(y,xs)
}
2015年5月12日火曜日
Scala関数型デザイン&プログラミング P34
Exercise2.3
カリー化では、引数2つの関数fが、fを部分的に適用する引数1つの関数に変換される。この場合も、コンパイルできる実装は1つだけである。この実装を記述せよ。
def curry[A,B,C](f:(A,B)=>C):A=>(B=>C) =
a=>(b=>f(a,b)) これは a=>b=>f(a,b)という書き方でいいのだろうか。
curryの返り値としては、aを決めれば b=>cつまりb=>f(a,b)となる関数ができる と理解していいのだろうか。
Exercise2.4
Curryによる変換を逆向きに行うuncurryを実装せよ。=>は右結合であるため、A=>(B=>C)はA=>B=>Cと記述できる。
def uncurry{A,B,C](f:A=>B=>C):(A,B)=>C =
(a,b)=>f(a)(b)
fは、aを引数として、b=>cとなる関数を返す関数
b=>cという関数がf(a) つまり bを引数としてf(a)という関数がf(a)(b)を返すという意味で
とらえるということと理解したが、これでいいのだろうか。
カリー化では、引数2つの関数fが、fを部分的に適用する引数1つの関数に変換される。この場合も、コンパイルできる実装は1つだけである。この実装を記述せよ。
def curry[A,B,C](f:(A,B)=>C):A=>(B=>C) =
a=>(b=>f(a,b)) これは a=>b=>f(a,b)という書き方でいいのだろうか。
curryの返り値としては、aを決めれば b=>cつまりb=>f(a,b)となる関数ができる と理解していいのだろうか。
Exercise2.4
Curryによる変換を逆向きに行うuncurryを実装せよ。=>は右結合であるため、A=>(B=>C)はA=>B=>Cと記述できる。
def uncurry{A,B,C](f:A=>B=>C):(A,B)=>C =
(a,b)=>f(a)(b)
fは、aを引数として、b=>cとなる関数を返す関数
b=>cという関数がf(a) つまり bを引数としてf(a)という関数がf(a)(b)を返すという意味で
とらえるということと理解したが、これでいいのだろうか。
2015年5月4日月曜日
Raspberry Pi 2 sdrサーバとしても利用
rtl_tcpを利用して、Sdrサーバ(FMラジオ等)としても、利用しようとしていたのですが、以前のraspberry Piのようにはうまくいきませんでした。いったん接続をやめると、2回目は接続できないという不具合は解消しませんでした。
いろいろ調べたものの解決方法はけっこう難しそうです。そこで、応急処置的ですが、PHPを利用して、rtl_tcpをシェルスクリプトでリスタートさせる方法をとってみたところ、何とか実用になりました。
PHPは、sdr#をロードしたときに、以下のように、呼び出すようにしてみました。
private void MainForm_Load(object sender, EventArgs e)
{
Encoding enc = Encoding.GetEncoding("Shift_JIS");
HttpWebRequest req =HttpWebRequest)WebRequest.Create("http://hostname/sdron.php");
WebResponse res = req.GetResponse();
Stream st = res.GetResponseStream();
StreamReader sr = new StreamReader(st, enc);
string html = sr.ReadToEnd();
sr.Close();
st.Close();
}
==sdr.sh== chmod +xで実行権限もたせる必要あり
#!/bin/sh
service rtl_tcp restart
==sdr.php==
<?php
exec("/home/pi/sdr.sh");
?>
==sdron.php==
<?php
exec("sudo php -f /var/www/sdr.php");
print_r("sdr recovery" );
?>
いろいろ調べたものの解決方法はけっこう難しそうです。そこで、応急処置的ですが、PHPを利用して、rtl_tcpをシェルスクリプトでリスタートさせる方法をとってみたところ、何とか実用になりました。
PHPは、sdr#をロードしたときに、以下のように、呼び出すようにしてみました。
private void MainForm_Load(object sender, EventArgs e)
{
Encoding enc = Encoding.GetEncoding("Shift_JIS");
HttpWebRequest req =HttpWebRequest)WebRequest.Create("http://hostname/sdron.php");
WebResponse res = req.GetResponse();
Stream st = res.GetResponseStream();
StreamReader sr = new StreamReader(st, enc);
string html = sr.ReadToEnd();
sr.Close();
st.Close();
}
==sdr.sh== chmod +xで実行権限もたせる必要あり
#!/bin/sh
service rtl_tcp restart
==sdr.php==
<?php
exec("/home/pi/sdr.sh");
?>
==sdron.php==
<?php
exec("sudo php -f /var/www/sdr.php");
print_r("sdr recovery" );
?>
2015年5月2日土曜日
RasPi2 クアッド コアの威力
SoftetherをRasPi2に入れてみた。Ipv6でつないだところ、トンネルの中のIPv4は、これまでの数倍速度アップしたようだ。
ただ、以前行ったクロスコンパイルの方法やaufsの入れ方は、だいぶ忘れていて、けっこう時間がかかってしまった。それに加えて、rasPi2のsdカードの接触が悪いせいか、ときどき起動しなくなることがあった。カードを差し込み直すと解消するという状態なので、いまひとつ安定性が心配だ。
ただ、以前行ったクロスコンパイルの方法やaufsの入れ方は、だいぶ忘れていて、けっこう時間がかかってしまった。それに加えて、rasPi2のsdカードの接触が悪いせいか、ときどき起動しなくなることがあった。カードを差し込み直すと解消するという状態なので、いまひとつ安定性が心配だ。
Java ダウンロード測度アップ
自作のグループウエアこれまで、ファイルのダウンロードは特に、Servletを使わず、<a href=のリンクからそのままダウンロードするようにしていたが、どうも遅いときがあるので、気になっていた。
試しに、Servletを使ってみたら、だいぶ早くなったような気がする。bufferの大きさもある程度大きくとってみた。以下を参考にさせていただいた。
http://www.syboos.jp/java/doc/file-download-by-servlet.html
ただ、問題は、全角のファイル名だと、ダウンロードがうまくいかない。いろいろ調べたら、けっこう面倒な対処が必要だと判明。以下のリンクで助けられました。
http://eiryu.hatenablog.com/entry/20120708/1341735000
試しに、Servletを使ってみたら、だいぶ早くなったような気がする。bufferの大きさもある程度大きくとってみた。以下を参考にさせていただいた。
http://www.syboos.jp/java/doc/file-download-by-servlet.html
ただ、問題は、全角のファイル名だと、ダウンロードがうまくいかない。いろいろ調べたら、けっこう面倒な対処が必要だと判明。以下のリンクで助けられました。
http://eiryu.hatenablog.com/entry/20120708/1341735000
2015年4月27日月曜日
raspberry pi 2 クロスコンパイルで一苦労
aufsを適用したカーネルにするために、クロスコンパイルをやってみるが、うまくいかない。
いろいろ原因を探ったところ、raspberry piの/bootディレクトリにあるカーネルは
kernel7.img
というファイルを使っていることが判明。
ネットでは、これがわからず、試行錯誤で分かった。
ちょっとしたことで、時間がかかってしまった。
いろいろ原因を探ったところ、raspberry piの/bootディレクトリにあるカーネルは
kernel7.img
というファイルを使っていることが判明。
ネットでは、これがわからず、試行錯誤で分かった。
ちょっとしたことで、時間がかかってしまった。
raspberry pi 2でWOL
okiro.phpというWOLのWebソフトを便利に使わせてもらっている。
今回、新versionのraspberry Pi2にも入れてみた。
久々と言うことで、細かい設定を忘れている。
PEARを使っていることを忘れている。
pear install Net_Ping
というコマンドで、インストールできて、無事動作するようになった。
今回、新versionのraspberry Pi2にも入れてみた。
久々と言うことで、細かい設定を忘れている。
PEARを使っていることを忘れている。
pear install Net_Ping
というコマンドで、インストールできて、無事動作するようになった。
2015年4月26日日曜日
HTML5 リッチテキストは便利だが
contentEditableの属性設定により、リッチテキストを扱えて便利だが、ひとつ問題が発生した。ワードの貼り付けがうまくいかないのである。通常のテキストボックスなら、単純なテキストが貼り付けられるから問題は起こらないが、ワードの場合、様々な書式も貼り付けされるため、データベースにうまく保存できず、エラーを起こしてしまう。
なんとか、タグを消して、テキストとして保存するようにしてみた。ただし、改行だけは、消さないようにした。
ただ、どうも統一性がとれておらず、応急処置的である。ここは、やはり、HTML5とワード文書等との連携も考慮に入れた仕様にしてほしいところである。
なんとか、タグを消して、テキストとして保存するようにしてみた。ただし、改行だけは、消さないようにした。
ただ、どうも統一性がとれておらず、応急処置的である。ここは、やはり、HTML5とワード文書等との連携も考慮に入れた仕様にしてほしいところである。
2015年4月4日土曜日
jqgridのeditoptionsでは、勝手にソートされてしまう
Jqgridを使って、各種データの設定がやりやすくはなっているが、ひとつ問題が出てきた。
ResultSet rs2= stmt2.executeQuery("SELECT * FROM shokuin");
....
jQuery("#list").jqGrid({
data: mydata,
datatype: "local",
colNames:['ID', 'グループ名', 'メンバー'],
// 編集可能にするセルを editable:true にします。
colModel:[
{index:'num', name:'num', width:50 },
{index:'name', name:'name', width:200, editable:true },
{index:'member', name:'member', width:250, editable:true ,edittype:'select' ,
editoptions:{multiple:true,value:{
<% int cou2=0;
while(rs2.next()){ if(cou2==0) { %>
<%=rs2.getString("id")%>:'<%=rs2.getString("name")%>'
<% } else { %>
,<%=rs2.getString("id")%>:'<%=rs2.getString("name")%>'
<% }
cou2=cou2+1; }
stmt2.close();
%>
}}},
],
.....
といった、具合に、グループのメンバーの登録に使ってきたが、rs2は、id順に勝手にソートされてしまうことに気づいた。ソートはidではなく、別に用意したsidという表示順を指定するための番号でソートしたいのだが、それができない。
毎年、人の入れ替えで転入者にidが振られるが、そのidの順番で並べて表示するのでなく
sidで並べて表示したいと思い、SQL文にorder by sidを追加してが、だめなのである。
http://www.trirand.com/blog/?page_id=393/discussion/edittype-select-and-editoptions-value-default-sorting
ネットでは唯一上記のリンクに少しヒントらしきものはあったが、どうやら、dataUrlというものを指定して、別のサーブレットから指定した順序にソートしたものを読み出すとよいようだ。
そこで、editoptions以下の部分をこんなふうに書き換えたらなんとか、動作させることができた。
editoptions:{value:"",multiple:true,dataUrl:'editoption'}
サーブレットのeditoptionは、<select>の要素を返すようにするとよいようだ。ただ、注意しなければならないのは、LFが入ってしまうので、これをreplaceAll("\\n","")などを使って、データベースに保存する前に削除する必要がある。なかなか、細かいところで、調整が必要である。もう少しスマートな方法がありそうだが。
ResultSet rs2= stmt2.executeQuery("SELECT * FROM shokuin");
....
jQuery("#list").jqGrid({
data: mydata,
datatype: "local",
colNames:['ID', 'グループ名', 'メンバー'],
// 編集可能にするセルを editable:true にします。
colModel:[
{index:'num', name:'num', width:50 },
{index:'name', name:'name', width:200, editable:true },
{index:'member', name:'member', width:250, editable:true ,edittype:'select' ,
editoptions:{multiple:true,value:{
<% int cou2=0;
while(rs2.next()){ if(cou2==0) { %>
<%=rs2.getString("id")%>:'<%=rs2.getString("name")%>'
<% } else { %>
,<%=rs2.getString("id")%>:'<%=rs2.getString("name")%>'
<% }
cou2=cou2+1; }
stmt2.close();
%>
}}},
],
.....
といった、具合に、グループのメンバーの登録に使ってきたが、rs2は、id順に勝手にソートされてしまうことに気づいた。ソートはidではなく、別に用意したsidという表示順を指定するための番号でソートしたいのだが、それができない。
毎年、人の入れ替えで転入者にidが振られるが、そのidの順番で並べて表示するのでなく
sidで並べて表示したいと思い、SQL文にorder by sidを追加してが、だめなのである。
http://www.trirand.com/blog/?page_id=393/discussion/edittype-select-and-editoptions-value-default-sorting
ネットでは唯一上記のリンクに少しヒントらしきものはあったが、どうやら、dataUrlというものを指定して、別のサーブレットから指定した順序にソートしたものを読み出すとよいようだ。
そこで、editoptions以下の部分をこんなふうに書き換えたらなんとか、動作させることができた。
editoptions:{value:"",multiple:true,dataUrl:'editoption'}
サーブレットのeditoptionは、<select>の要素を返すようにするとよいようだ。ただ、注意しなければならないのは、LFが入ってしまうので、これをreplaceAll("\\n","")などを使って、データベースに保存する前に削除する必要がある。なかなか、細かいところで、調整が必要である。もう少しスマートな方法がありそうだが。
2015年3月30日月曜日
Win8.1ダウンロード版の問題
・最近のWindowsのダウンロード版を購入には、手間がかかる。
注文してから、4、5時間後にダウンロードできると書いてあるが、半日以上たってもできない。結局、店で購入した方がいいということで、キャンセル。セキュリティがきびしくなっているからだという説明だったが。。。
・Windowsそのものを、使い続ける必要がどの程度あるか、よく検討していった方がいい時期にきているのかもしれない。
・今回32bit版のWin8.1(ダウンロード版)は持っていたが、これを64bit版に移行しようと試みたが、だめみたいだったので、仕方なくWin8.1を新たに購入することに。
注文してから、4、5時間後にダウンロードできると書いてあるが、半日以上たってもできない。結局、店で購入した方がいいということで、キャンセル。セキュリティがきびしくなっているからだという説明だったが。。。
・Windowsそのものを、使い続ける必要がどの程度あるか、よく検討していった方がいい時期にきているのかもしれない。
・今回32bit版のWin8.1(ダウンロード版)は持っていたが、これを64bit版に移行しようと試みたが、だめみたいだったので、仕方なくWin8.1を新たに購入することに。
2015年3月26日木曜日
プロキシーの認証
プロキシーに認証が入るようになった。
いろいろ影響がでるようだ。
1 これまで使っていたソフトも、これにひっかかってしまう。とりあえず、vb.netで作ったソフトにはローカルでしか使わないので
Dim wc As New System.Net.WebClient()
wc.Proxy = Nothing
のようなことをすればよいようだ。
http://dobon.net/vb/dotnet/internet/useproxy.html
2 Linuxのwgetについては
~/.wgetrc に、追加するものとして
use_proxy = on
proxy_user = ユーザー名
proxy_passwd = パスワード
http_proxy = http://ホスト名:ポート名
https_proxy = http://ホスト名:ポート名
ftp_proxy = http:////ホスト名:ポート名
http://d.hatena.ne.jp/taiyo/20080401/p2
3 apt-getについては
/etc/apt/apt.confに追加するものとして
Acquire::ftp::proxy "ftp://ユーザー名: パスワード@ホスト名:ポート名/";
Acquire::http::proxy "http://ユーザー名: パスワード@ホスト名:ポート名/";
Acquire::https::proxy "https://ユーザー名: パスワード@ホスト名:ポート名/";
http://d.hatena.ne.jp/mrgoofy33/20100726/1280154695
なかなかめんどうである
いろいろ影響がでるようだ。
1 これまで使っていたソフトも、これにひっかかってしまう。とりあえず、vb.netで作ったソフトにはローカルでしか使わないので
Dim wc As New System.Net.WebClient()
wc.Proxy = Nothing
のようなことをすればよいようだ。
http://dobon.net/vb/dotnet/internet/useproxy.html
2 Linuxのwgetについては
~/.wgetrc に、追加するものとして
use_proxy = on
proxy_user = ユーザー名
proxy_passwd = パスワード
http_proxy = http://ホスト名:ポート名
https_proxy = http://ホスト名:ポート名
ftp_proxy = http:////ホスト名:ポート名
http://d.hatena.ne.jp/taiyo/20080401/p2
3 apt-getについては
/etc/apt/apt.confに追加するものとして
Acquire::ftp::proxy "ftp://ユーザー名: パスワード@ホスト名:ポート名/";
Acquire::http::proxy "http://ユーザー名: パスワード@ホスト名:ポート名/";
Acquire::https::proxy "https://ユーザー名: パスワード@ホスト名:ポート名/";
http://d.hatena.ne.jp/mrgoofy33/20100726/1280154695
なかなかめんどうである
2015年3月22日日曜日
HTML5は発展途上
グループウエアにリッチテキストで(といっても、Bold,アンダーライン、文字色、フォントサイズ等の基本的なもののみ)編集できるようなものはないかと探していたところ、Jqueryには様々なものがあるが、どれも、現在使っているものには合わない。
1ページの中で、ポップアップウインドウをjqueryで入力画面を出しているので、ソースの細かい部分で調整しないと、うまく整合性を保てない。
HTML5が、意外と使いやすくなってきていることを知り、使ってみた。
http://blogs.msdn.com/b/osamum/archive/2014/02/14/html5api-contenteditable.aspx
上記のサイトが参考になりました。
contentEditable という属性により、div要素をリッチテキストとして編集できるので、便利である。
いくつか注意点をあげると
①このままでは、スクロールしないので、スクロールの機能をつける方法をネットで調べると
.scr { overflow: scroll; }
として、div要素のclassをscrとしてやればよいことが判明。
参考サイト:http://www.htmq.com/style/overflow.shtml
②Chromeだと問題ないが、IE11では、行間がかなり広がって、表示がうまくいかない。これも、ネットで解決方法を調べた。
.htmlbox p { margin:0; padding:0; } というスタイルシートにして
広がってしまうdiv要素のclassをhtmlboxとするとよかった。
ただ、この方法は応急処置的という感じもする。IE11は、完全にHTML5に対応してないということだろうか?
HTML5は、便利だが、発展途上といったところだろうか。
参考サイト:http://arinogotokuatumarite.blog19.fc2.com/?no=101&sp
1ページの中で、ポップアップウインドウをjqueryで入力画面を出しているので、ソースの細かい部分で調整しないと、うまく整合性を保てない。
HTML5が、意外と使いやすくなってきていることを知り、使ってみた。
http://blogs.msdn.com/b/osamum/archive/2014/02/14/html5api-contenteditable.aspx
上記のサイトが参考になりました。
contentEditable という属性により、div要素をリッチテキストとして編集できるので、便利である。
いくつか注意点をあげると
①このままでは、スクロールしないので、スクロールの機能をつける方法をネットで調べると
.scr { overflow: scroll; }
として、div要素のclassをscrとしてやればよいことが判明。
参考サイト:http://www.htmq.com/style/overflow.shtml
②Chromeだと問題ないが、IE11では、行間がかなり広がって、表示がうまくいかない。これも、ネットで解決方法を調べた。
.htmlbox p { margin:0; padding:0; } というスタイルシートにして
広がってしまうdiv要素のclassをhtmlboxとするとよかった。
ただ、この方法は応急処置的という感じもする。IE11は、完全にHTML5に対応してないということだろうか?
HTML5は、便利だが、発展途上といったところだろうか。
参考サイト:http://arinogotokuatumarite.blog19.fc2.com/?no=101&sp
2015年3月17日火曜日
sambaを使っているPCのHDD交換
共有サーバのHDDを交換したいのだが、できるだけ、サーバの使用の中断時間をすくなするにはどうするかで、いろいろ考えてみた。
・データを移動するという方法がわかりやすいが、誰かが、ファイルを使っているとたぶん、うまく移動しないだろう。
・とりあえず、コピーしてみる。しかし、すべてコピーし終わるのに、相当時間がかかるから、その間に、すでにコピーしたはずのファイルの元ファイルが、書き換えられてしまっている可能性もなくはない。
・そこで、一度、コピーしたら、そのコピーしている時間の範囲に書き換えられたファイルだけ、指定してコピーする。(fastcopyなど使えばできそうだ)それだったら、短時間で済む。その間だけ、少し使用を中断させてもらえば、極力迷惑はかからないのではないかと。まずは、やってみないことにはわからないが。
***********************
実際やってみたら、fastcopyなどより、bunbackupなどのほうが、コピーに失敗した場合、履歴が残るのでいい。
Windowsで、タスクスケジューラで、夜間のコピーもやってみた。なんとか、解決
・データを移動するという方法がわかりやすいが、誰かが、ファイルを使っているとたぶん、うまく移動しないだろう。
・とりあえず、コピーしてみる。しかし、すべてコピーし終わるのに、相当時間がかかるから、その間に、すでにコピーしたはずのファイルの元ファイルが、書き換えられてしまっている可能性もなくはない。
・そこで、一度、コピーしたら、そのコピーしている時間の範囲に書き換えられたファイルだけ、指定してコピーする。(fastcopyなど使えばできそうだ)それだったら、短時間で済む。その間だけ、少し使用を中断させてもらえば、極力迷惑はかからないのではないかと。まずは、やってみないことにはわからないが。
***********************
実際やってみたら、fastcopyなどより、bunbackupなどのほうが、コピーに失敗した場合、履歴が残るのでいい。
Windowsで、タスクスケジューラで、夜間のコピーもやってみた。なんとか、解決
登録:
投稿 (Atom)