goでも (4)
兄貴に誘われて東京へ行ってきた。観光目的。兄貴夫婦が京都へ紅葉見物に行きたかった らしいけど、あちらはハイシーズンで宿なんて取れるはずない。諦めて、オイラーに 道案内させようという寸法で誘われた次第。
寒冷地仕様の服装で行ったら、東京はハワイみたいに暑かった。ハワイと思って楽しんで きたよ。物価がハワイ並みだったのは頂けなかったけど。
折角来たんだから、神保町の中古書店街へ連れて行けってのが、第一指令。岩波の絶版に なった本を探したいとの事。ぶらぶらしながら探したけど見つからず。
何軒目かの店におばあちゃんが店番してた。著名を告げると、台帳からインデックスを 検索。それで店内を探してもらうも在庫無し。親切な事に扱っていそうな店を教えて くれた。そしてインデックス番号の 岩波青XXXってのを言うと、よその店でも扱い 易いよとメモを渡してくれた。
そうして、一軒目の店で目出度くHitしました。定価600円ぐらいな文庫本が、2300円 ですって。何でも鑑定団の世界ですな。まあ、マニアはお金を幾ら積んでも、欲しい物を 手に入れるんだな。
次は、浅草へ行け。雷門の提灯が松下電器寄贈とは初めて知りましたよ。仲見世通りは、 酉の市と相まって大混雑。外国人は半分とは恐れいりました。
次は渋谷のスクランブル交差点に立ってみたいと言う指令。地下鉄1本、30分でご到着で 楽で良かった。ハチ犬の頭を撫でると、一生犬に襲われないと偽情報を流すと本気に してたぞ。混雑過ぎて、犬に近づけませんでしたけど。
道玄坂を登って、本場のデパート体験、東急本店へ。ジュンク堂と丸善が合体して店を 出してた。兄貴は、買えばうん万円とかの本を眺めておりましたよ。
翌日は、上野公園の都美術館へ。フィレンツからの美術館が出店展示してた。 オイラーにはちんぷんかんぷん。宗教画みるなら、国立博物館の仏像の方がオイラーには良かったかも? 出口に売店が有って、公式目録を売ってた。ここで今しか買えないから記念にどうぞって ささやいたら、いそいそと購入してましたよ。
次の指令は、銀座へ連れてけ。有楽町の交通会館で、各藩のお国名産品陳列販売所を 視察。蝦夷藩とか越中藩と紀州藩とか出てたな。昼食後、銀座方面へ流して 行くと、途中に山形と広島のアンテナショップが有ったぞ。オイラーは広島名物を Get。だって、あちらへは行く事無いもん。
キムラヤのアンパンを(無理して)食べながら銀座ブラブラ。 ワコーは田舎者はお呼びじゃ無いって雰囲気なんで、三越のライオンさんをナデナデ。 猫族に襲われない御利益あるのかな? 猫族より熊の方が田舎では、切実な問題です。ああ、いのししの 方が、もっと切実か。
折角なんで歌舞伎座もいいでっせと御提案。地下の売店で、東京らしい 土産をGet。パンフレットを眺めた兄貴は、観覧料が2万円には腰を抜かしておりましたよ。 疲れたから、もう帰ろうの一言で、お江戸を後にしましたとさ。
読書メーター 7冊 / 1924頁 / 11000円
Xming
前回のFreeBSDの話の続き。Xが動かなくなったものだから、X飛ばしをウブでやった。X機能が 欲しいためにウブを上げるのも何だか負けてるぞ。
そこで、Windows7にXのマネをさせよう。 フリーのWindows用Xサーバー「Xming」のインストールと基本設定、使い方 とか、PuTTY + Xming でX を使おう を参考にXmingを入れた。
Xmingってが有る事は昔から知ってたけど、今まではなるべくWindowsとは疎な結合が良いと 思って、使う事は無かったのさ。今回初めて、重い腰を上げたって訳。PuTTYは昔から使ってるから、 Xmingを入れる時は、そんなの不用って指定したぞ。
注意点として、PuTTYの設定の、SSH->X11の所で、X11フォワーディイングを有効にして、 Xディスプレーの場所を localhost:0 と設定する事。こうしておかないと、Xが使う6000番ポートに 描画情報が流れていかず、表示出来ない状態になってしまう。
[sakae@fb10 ~]$ emacs -r & [1] 1033 [sakae@fb10 ~]$
一つ注意する事は、Xのアプリをバックグラウンドに追いやっておく事。これを怠ると ちと面倒な事になる。それさえ注意すれば、快適。
快適なので、ウブでも体験しようと思ったら、どうもWindows7側にアプリが出てこない。 いろいろ調べたら、フォント関係のサービスが動いていないっぽい。xfstt を入れたら、 やっと動き出した。お疲れさん。
Go本
今まで、goの資料としてWEBDBプレスの特集記事を見てたんだけど、goが21世紀のC言語と 悟ったので、本を1冊調達しておく事にした。。。
したはいいんだけど、こんな田舎の本屋に置いてあるはずが無い。何をくだらん事で悩んで る! そんなの尼でポチッれば済む事じゃん。
オイラー、伝統的に尼は嫌い。日本でぼろ儲けしてるくせに、ちゃんと税金を払わん、マフィアに 尻尾を振れるか。酷税庁も、恐い者には手を出さんからなあ。
e-hon経由で、書店留で頼んだ。東販がとなみ運輸で、 密閉して送ってきたぞ。包みには、受取人の氏名と伝票番号と支払うべき値段しか書いてない。 書店の人には、何を頼んだかは分からないので、怪しいものも簡単に依頼できますよ。
で、頼んだのは、『基礎からわかるGo言語』。ソファーにひっくり返って拾い読みするのには うってつけ。逆引きサンプルがあれば、観光案内には最適だな。
今まで、地図を見ずにあちこち勝手に歩いていたけど、これからは案内人がいるので、楽に なるだろう。
現役時代、あちこち出張の折、初めての街の降り立った時、真っ先に行くのはインフォメーション センター。そこで地図を貰い、地下鉄なりバスなりの一日乗車券の買い方を教わって、 見知らぬ街へGo。今の時代だと、スマホで一人もくもくとするんでしょうけど。。
無駄な事?
goで血圧アプリを書いている。大体出来たんだけど、インタープリタ系と違ってコンパイラ型は 真っ直ぐに(速く)走るだけ。ちょいとパラメータを変えて実験という訳にはいかない。
インタープリタ系、例えばRubyだと、ソースコードがあの人設計の仮想CPUで実行出来るように その場で変換してるんで、コンパイラーを内蔵してるって考えて良い。そして、変換結果は メモリー上に保持されるのが普通だ。
goの場合は、インテルの石とかにコンパイルされてから実行してる訳。しかもJITなんて言う 取ってつけたような技じゃなくて、最初からネイティブコードだし。だけど欠点が有って 、ソースの変更する度に ユーザーがコンパイルを指示してあげなければいけない。変換結果はDiskの中に残される。
おいらのgo開発環境はemacs上なんだけど、 自分がちょいと書いたemacsコードによって、2キーストロークで、コンパイルと実行をこなして くれる。こうなると、goのreplを使ってる感覚になるな。
なるべく速くコンパイルして欲しいぞ。今は、こんな状態。
sakae@uB:~/godev/src/bld$ time go build bld.go real 0m3.014s user 0m0.232s sys 0m0.968s sakae@uB:~/godev/src/bld$ time go build bld.go real 0m0.518s user 0m0.244s sys 0m0.260s
初回は、コンパイラーとかリンカーとかのもろもろな物がメモリーに載っていないので、時間が かかる。でも、2回目からは、diskキャッシュのおかげで、大幅にコンパイル時間が短縮される。
だったら、コンパイルの作業領域で/tmpを最初からメモリーに割り当てておいたらどう? そうなればgoのハンディキャップは無くなるはず。 いわゆる、RAM DISKね。巷ではSSDとか言って持て囃されているけど、それよりは速いはず。
ってんで、/tmpがRAMエリアになってるか調べたら、うぶなやつは、なっていなかった。 どうやって、/tmpをRAMに割り当てるか調べたら、
tmpfs /tmp tmpfs defaults,noatime,mode=1777 0 0
こんなのを/etc/fstabに書いておいて、rebootすればいいらしい。早速やってみたよ。 そしたら、
sakae@uB:~/godev/src/bld$ df Filesystem 1K-blocks Used Available Use% Mounted on /dev/sda1 31863728 3182720 27039384 11% / tmpfs 387004 16 386988 1% /tmp
こんな具合になった。これで速くなるかと思ったら、以前と全く変わらなかった。 たかが、2Mそこらのファイルをハンドリングするぐらいじゃ、効果ないんだろうな。
じつは、これを確認する前に、Windows機でRAM Diskってどうやるのって調べていたら、 Firefoxが劇速になるとかの題で、取り上げられていた。 無料RAMディスク作成ソフト一覧 とか、RamDisk for Windows7にね。
goをLLっぽく使う
goをLL感覚で使う為、mainは下記のようにしてみた。
func main() { mycsv("current.csv") z := bld // select or fallthrough z = frm(1308, z) z = utl(1310, z) // z = eq(1311, z) // choose one or fallthrough z = am(z) // z = pm(z) // select or fallthrough // z = hd(50, z) // z = tl(30, z) // select pp(z) ss(z) lg(hi, z) }
使いたいフィルターの所のコメントをon/offして、パラメーターを変更してからrun。 今回eqなんてのを追加した。指定した年月のデータを拾い出す仕様。それから、グラフ書きは 線2本にした。だって、線色がみな 同じで混同しちゃうから。
こういう風な、コードの選択って、 コードのパッチだな。パッチって、配線って意味があるのね。昔のコンピュータは、 プログラミングを配線の繋ぎ変えで行っていた。パッチボードという配線板が用意されていて、 そこに線を繋ぐ事で、演算器を相互接続してく訳だ。それが転じてプログラムのソースの 事をコードなんて言う。だから、コード・コードと騒ぐ人は年季の入った人と思っていれば、 間違い無い。なお、SICPの5章だったかには、その演算器を接続してプログラムする例が、 図入りで出てる。
ああ、パッチが転じてって事なら、もう一つ例が有った。最近読んだ、『明治維新の犬たち』と いうのに、犬の名前は、ぽちってのが多いけど、その由来は? ってのが出てた。 それによると、ぽちぽちと班点のある犬を外人のやつらは、つぎはぎだらけの犬とみなしてた。 つぎはぎは英語でパッチ。それが日本人にはポチって聞こえたそうな。それが転じて、 犬の名前にはポチが多いんだとか。
その前は、外国人居留地にいた外人が犬を呼ぶ時、come hereと号令した。そこからカムが カメに聞こえたもんだから、カメって名前の犬も多かったそうな。維新の頃は、町犬、里犬は 沢山いれど、個人で飼うことは無かった。だから名前を付ける必要が無かった。やがて、 外人の真似をして個人飼育が始まると、名前を付ける必要が生じた。それで、外人に習って、 カメとかポチって名前が流行ったとか。
その後、外国から輸入された狂犬病撲滅の為、飼い主のいない犬は処分されるようになり、 のさばっていた犬達は激減したとか。犬とっちゃ、いい災難ですなあ。
go + gnuplot
グラフ書きは、やっぱりgnuplotに外注するかなあ。goのプロジェクトを検索すると連携用の パッケージも開発されているようだけど。。
os/execの例から、外注さんのコントロール方法を学んだ。もとえ、コピペしてきた。
s := fmt.Sprintln("plot '-' w l") for i, v := range w(idx, ds) { s += fmt.Sprintln(i, v) } s += fmt.Sprintln("end") cmd := exec.Command("gnuplot", "-p") cmd.Stdin = strings.NewReader(s) err := cmd.Run() failOnError(err) fmt.Scanln(&s) // keep running go on emacs(kill for C-x k)
前半部分は、グラフ職人に与える指示書を作っている。単純に文字列を連結してるけど、この 方法は効率が悪い事が判明してます。 ちゃんとやるなら、Go言語で効率良く文字列を連結する話 #golang を見て、対処しましょう。
後半部分では、os/execパッケージを使う。 まず、Commandを使って、外注さんを登録する。引数は本体とは分離して登録するのね。Stdinで、依頼内容を パイプに充填する。NewReaderの引数sは、gnuplotへの指示書を文字列になったものだ。 用意が整ったら、Runで仕事を開始。後はエラーでブースカ文句が出ないか確認。 本当は、細かい文句も聞いてあげればいいんだけど、まあ、リーチンワークだからってんで省略。
最後のScanlnは、emacsから動かした時、goが終了すると同時にgnuplotの画面が閉じてしまうので、 goが踏み止まるように入れている。gaucheでも、同じ事を経験したな。
Windows7でもやってみようとして、消していたwgnuplotを再度入れ直した。でもgnuplotをgoが認識しない。 おかしいなPATHが通っていないんかな? echo %PAT% するも、表示されたデータに目眩が しましたよ。こういう時は、分かり易く表示すべし。
package main import "fmt" import "os" import "strings" func main() { s := os.Getenv("PATH") for _,v := range strings.Split(s, ";"){ fmt.Println(v) } }
パッケージの地理感が出てきたので、すらすらと書けたよ。こういう使い捨てをコンパイル して実行するかってのは、有りますけどね。それにしても、型のstringとパッケージのstringsと 一字しか違いがなくて、紛らわしいな。importする時、別名を付けるのがいいかな。
で、結果は、34個もPATHが登録してあった。中にはもう使っていないものを含まれていたぞ。 思い切って、整理しておくかな。PATHを編集するあの糞I/Fは、いつまでたっても腹が立つぞ。
昔のgnuplotは、binaryなんてdirになってたのね。今はbinになってるし、wgnuplotも メニューとヘルプが日本語になってたぞ。パイプが使えるのもunixのそれと同一になってるおかげで、 unix上で作ったgoソースが、無修正で動いた。素晴らしい。
パイプ風に
上で、コードの切り貼りによるLLっぽい挙動をやった。これってJITが走っている訳で、裏は goが支えている。逆に言えば、goがインストールされていない環境じゃ使えない訳。
クリスマスも近いので、主治医に自家製血圧ノートプログラムをプレゼントしようと思ったら 大変な訳だ。何とかアプリ1本にまとめたいぞ。で、グラフ職人の事は後で考える事にして (これぞ日本のお家芸、先延ばし。かっこよく言うと、遅延評価だな)、 それ以外(切り貼り)の事を考えてみる。goのアプリへの入力は、インタラクティブが無難 なんだけど、オイラーの趣味で、コマンドラインから一気に与えたい。 そう、パイプ風にね。
以前、コマンドライン入力(いわゆる、引数の取り込み)を処理 するのに2つの方法が有る事を知った。一つは、os.Argsって言う、馬鹿入力方式。もう 一つはインテリジェントなflagパッケージを使う方法。
今回は馬鹿を相手にせず、Golang Cafe #14 まとめ flagパッケージ に挑戦してみる事にする。実行イメージとしては、こんなのだ。
sakae@uB:~$ ./bld -eq 1411 -am -ss
14年11月の起床時データを抽出して、それの統計サマリーを出力して、って具合。 他には、
sakae@uB:~$ ./bld -frm 1406 -utl 1408 -pm -lg low
夏の夜の(あれ? 夏って6月から8月まで? 最近の日本は、四季じゃなくて、冬と夏しか 無いような。。。)最低血圧変動をグラフで見たーーい。 こんなのが、出来ればいいな。頑張って書いてみたぞ。if文の羅列になっちゃったけど。
最初、if文の羅列じゃカッコ悪いと思い、switchとcaseとfallthroughの組み合わせを試して みたんだけど、旨く制御出来なかった。原因はfallthroughした時、次のcase式が無視されて しまう事による。条件を満たす複数のブロックを実行したい場合は、switchは使えないのね。
おかげで、行数が長くなったぞ。何行あるかな? 248行有った。clojureのそれは、122行 だから、2倍だな。抽象度が低いのかな。それとも、無闇に行数を稼ぐ閉じブラケットのせいかな?
閉じブラケットと言えば、rubyもそうだな。matzさんの趣味が反映されてて、endが雁のように 隊列を為しているからなあ。近頃はさっぱりrubyのコードを書かなくなっちゃったんで、 誰か、同じ仕様で書いてみて。
ああ、出来栄えを載せておくか。
sakae@uB:~/godev/src/bld$ ./bld 13010103 to 13123121 data having. type 'bld -h' to see command options.
引数無しで実行すると、収録されてる開始日と終了日を、取り合えず報告。痴呆になっても 大丈夫なように、ヒントの出し方を示唆。これで分からなかった、即病院へ行け。
sakae@uB:~/godev/src/bld$ ./bld -h Usage of ./bld: -am=false: Pick wakeup data -eq=1411: Pick YYMM's data -frm=1001: Pick from YYMM's data -hd=10: Pick first n data -lg=false: Show line graph -pm=false: Pick at_night data -pp=false: Show picked data -ss=false: Show stats summary -tl=10: Pick last n data -utl=9912: Pick until YYMM's data
使えるオプションを確認。余計なお世話でアルファベット順に羅列してくれちゃってる。 それに、もう少し整形して欲しかったなあ。
Pickと付いているのが、フィルター系、Showと付いているのが、いわゆるパイプの終端に位置 する、結果の表示系。 -eq=1411 のように、数字が有るやつは、設定してなんぼのオプション。-am=false のように なってるのは、指定する事によってtrueになり、その機能が実行される。
sakae@uB:~/godev/src/bld$ ./bld -eq 1312 -ss -pm size: 31 min: 99.0 56.0 57.0 mean: 114.3 64.1 64.8 max: 130.0 74.0 74.0 std: 8.2 4.7 3.6 sakae@uB:~/godev/src/bld$ ./bld -ss -pm -eq 1312 size: 31 min: 99.0 56.0 57.0 mean: 114.3 64.1 64.8 max: 130.0 74.0 74.0 std: 8.2 4.7 3.6
オプションの並びは、任意。評価順番は、コードの中に埋め込んである。 これは、将来に備えて、少し馬鹿になっても動かせるようにする為です。
馬鹿でも動かせると言えば、その筆頭は、Webのブラウザーだな。あいつは何たって、 クリック猿用の入出力装置ですから。
そうか、このプログラムも究極は、Webに載せちゃう事だな。えと、どうやればいいんだ。 コマンドオプションの入力部分を、Webのformで表現すればいいんだな。
そして結果をhtmlで返すとな。この方法なら、グラフもグラフ職人に頼んで、pngなり svgで出力出来るから、楽にいきそうだな。
最近のWebは、ソープだRESTだとか新用語が乱発されてるな。なんだって、ルーティング なんてのも有るんか。URLに応じて、挙動を変える。だったら、患者名をURLに埋め込んで、 CSVファイルを選定してあげれば、DBもどきを使ってる事になるな。今流行りのNoSQL なんちゃってね。
想像は膨らむけど、Webは昔、反吐が出る程やったので、もうやらない。さらっと、Go本でも 眺めて終わりにしよう。なお、下記に掲載したコードでは、簡単に落とせますので、Webに 載せるなら、事故責任で強化してください。当方一切責任放棄。
Go本は入門者用と言う事で、難しい事は書いてない。Netをさ迷っていたら、 Golang のオフィシャルが提供するインタフェースまとめ なんてのに出会った。インターフェースを旨く使いこなすのがgo制覇の道とは、激同意。
go言語による血圧管理プログラム
package main import ( "encoding/csv" "flag" "fmt" "github.com/kr/pretty" // http://godoc.org/github.com/kr/pretty "math" "os" "os/exec" "strconv" "strings" ) type AAy [][4]int // main data type var bld AAy // blood data const ( // rows index name 0 .. 3 ymdh = iota hi low pls ) func failOnError(err error) { if err != nil { panic(err) } } func mycsv(csvfile string) { var rows [4]int fd, err := os.Open(csvfile) failOnError(err) defer fd.Close() reader := csv.NewReader(fd) all, err := reader.ReadAll() failOnError(err) for _, el := range all { for i, v := range el { rows[i], err = strconv.Atoi(v) failOnError(err) } bld = append(bld, rows) } } func pp(obj interface{}) { pretty.Printf("%# v\n", obj) } func w(i int, ds AAy) []int { // take hi,low or pls var rs []int for _, el := range ds { rs = append(rs, el[i]) } return rs } func hd(n int, ds AAy) AAy { return ds[:n] } func tl(n int, ds AAy) AAy { return ds[len(ds)-n:] } func am(ds AAy) AAy { var rs AAy for _, el := range ds { if el[ymdh]%100 < 12 { rs = append(rs, el) } } return rs } func pm(ds AAy) AAy { var rs AAy for _, el := range ds { if el[ymdh]%100 >= 12 { rs = append(rs, el) } } return rs } func frm(ym int, ds AAy) AAy { var rs AAy lmt := ym * 10000 for _, el := range ds { if el[ymdh] > lmt { rs = append(rs, el) } } return rs } func utl(ym int, ds AAy) AAy { var rs AAy lmt := ym*10000 + 3124 for _, el := range ds { if el[ymdh] < lmt { rs = append(rs, el) } } return rs } func eq(ym int, ds AAy) AAy { var rs AAy for _, el := range ds { if el[ymdh]/10000 == ym { rs = append(rs, el) } } return rs } func lg(ds AAy) { s := fmt.Sprintln("plot '-' w l") for i, v := range w(hi, ds) { s += fmt.Sprintln(i, v) } s += fmt.Sprintln("") for i, v := range w(low, ds) { s += fmt.Sprintln(i, v) } s += fmt.Sprintln("end") cmd := exec.Command("gnuplot", "-p") cmd.Stdin = strings.NewReader(s) err := cmd.Run() failOnError(err) // fmt.Scanln(&s) // keep running go on emacs(kill for C-x k) } func min(a []int) float64 { rs := math.MaxInt32 for _, v := range a { if v < rs { rs = v } } return float64(rs) } func max(a []int) float64 { rs := math.MinInt32 for _, v := range a { if v > rs { rs = v } } return float64(rs) } func mean(a []int) float64 { s := 0 for _, v := range a { s += v } return float64(s) / float64(len(a)) } func std(a []int) float64 { m := mean(a) s2 := 0.0 for _, v := range a { s2 += (float64(v) - m) * (float64(v) - m) } return math.Sqrt(s2 / float64(len(a))) } func ssf(fn func([]int) float64, a3 [][]int) string { rs := "" for _, v := range a3 { rs += fmt.Sprintf("%6.1f", fn(v)) } return rs } func ss(ds AAy) { var a3 [][]int a3 = append(a3, w(hi, ds), w(low, ds), w(pls, ds)) fmt.Printf("size: %d\n", len(ds)) fmt.Println("min: " + ssf(min, a3)) fmt.Println("mean: " + ssf(mean, a3)) fmt.Println("max: " + ssf(max, a3)) fmt.Println("std: " + ssf(std, a3)) } func main() { var veq *int = flag.Int("eq", 1411, "Pick YYMM's data") var vfrm *int = flag.Int("frm", 1001, "Pick from YYMM's data") var vutl *int = flag.Int("utl", 9912, "Pick until YYMM's data") var vhd *int = flag.Int("hd", 10, "Pick first n data") var vtl *int = flag.Int("tl", 10, "Pick last n data") var bam *bool = flag.Bool("am", false, "Pick wakeup data") var bpm *bool = flag.Bool("pm", false, "Pick at_night data") var bpp *bool = flag.Bool("pp", false, "Show picked data") var bss *bool = flag.Bool("ss", false, "Show stats summary") var blg *bool = flag.Bool("lg", false, "Show line graph") flag.Parse() args := "" flag.Visit(func(f *flag.Flag) { args += fmt.Sprintf(":%s: ", f.Name) }) // fmt.Println(args) // monitor selected options mycsv("current.csv") z := bld if *bpm && strings.Index(args, ":pm:") >= 0 { z = pm(z) } if *bam && strings.Index(args, ":am:") >= 0 { z = am(z) } if strings.Index(args, ":eq:") >= 0 { z = eq(*veq, z) } if strings.Index(args, ":frm:") >= 0 { z = frm(*vfrm, z) } if strings.Index(args, ":utl:") >= 0 { z = utl(*vutl, z) } if strings.Index(args, ":hd:") >= 0 { z = hd(*vhd, z) } if strings.Index(args, ":tl:") >= 0 { z = tl(*vtl, z) } if *bpp && strings.Index(args, ":pp:") >= 0 { pp(z) } if *bss && strings.Index(args, ":ss:") >= 0 { ss(z) } if *blg && strings.Index(args, ":lg:") >= 0 { lg(z) } if args == "" { fmt.Print(bld[0][ymdh], " to ") fmt.Println((bld[len(bld)-1][ymdh]), "data having.") fmt.Println("type 'bld -h' to see command options.") } }
コード説明と言うかメモ
将来の自分の為に、メモを残しておく。だったらコメント入れとけ、ごもっとも。
ppはprintみたいに、どんな型でも型に嵌まらずに受け取って欲しい。goみたいに硬いやつに そんな事出来るんか。printみたいに出来てるんで出来るんでしょう。秘密は、interface{}と 言うマジックな型宣言。これで、goが骨抜きになるよ。少なくても表面的には。 こういうのocamlで言う所の多相型って言うんだっけ? あれ、同等のものがhaskellに あったかなあ。
goで、関数の引数に関数を渡せるか。それが出来れば、
fmt.Println("mean: " + ssf(mean, a3))
みたいな事が、簡単に実現出来る。meanは、整数の配列を受け取って、それの平均をfloat64 にして返します。このように、配列を受け取って何か(平均とか最大、最小)をする関数 シリーズがあれば、後は、その関数を引数にしていろいろ出来る訳。 今回は、その何かは、float64の清家だけどね。
func ssf(fn func([]int) float64, a3 [][]int) string
こんな風に、関数の型を宣言します。(関数の)仮引数の名前は、fnってしといた。 関数だからと言って、特別扱いすることなく使えるのはlispな人には嬉しいぞ。なお、関数名も 変数名も同列に扱う、いわゆるLisp-1の世界管で動いていますよ。
flag.Visit(func(f *flag.Flag) { args += fmt.Sprintf(":%s: ", f.Name) })
mainの中で、コマンドラインに使われたオプション名を取り出して、文字列argsに登録してる。 Visitと言う関数の中で、いきなり無名関数を定義・実行してる。schemeで言う所のlambda式が 出てきてて、面白いな。 goは、隠れschemeと言っても過言ではないかも。そうそう、オプションの名前の前後をコロンで 囲っているのは、文字列検索の都合です。(utlとtlがバッティングする為)
まあ、このあたりは、javascriptでも同じ事が出来る。web屋さんに抵抗なく使って貰うには、 javascriptを意識しとかにゃいかんと言うのは、肯ける所ですな。
ぐぐる様は、javascriptを置き換えようとdartとか言うのを出してきてるんで、社内抗争勃発 なんて事にならなければ良いのですが。それとも、きちんと住み分けしてて、よその島は 荒らさないって事で手打ちしてんのかな。(宿の島は中国マフィアで袋は台湾系とか)
両者の発展を祈って、お手を拝借。フレー、フレー、GoGoGO. がんがれ、dart、darT、daRT、dART、DART。 あっちの島へ行くなら、ほら。 dartrefjp