バグレポート

そのまま公開するとまた面倒臭い事になりますから、Timeeingine はいくら好意的に解釈しても大きいバグが二つ存在するので直したほうがよいとだけ。("store" は問題外でカウントに入りません)

gpg+base64 してあります。鍵を公表する事がなければそれでよし。

魚拓: http://megalodon.jp/2016-0515-0415-36/d.hatena.ne.jp/camlspotter/20160514

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

Tシャツを印刷するには

utme http://utme.uniqlo.com/ が日本ではちょっと流行っているようです。一枚から。1990円。私もデザインだけしてみました:



シルクスクリーンは品質は良いんですけど、スクリーンを作る必要上、フルカラーは無理(普通は単色で、地色とのコントラストにあなたの感性が問われる)そして枚数が少ないと単価が恐ろしいことになりますね。数年前に50枚ほど作ったときは一枚1500円以下に抑えられましたが…一枚だけ欲しいときは無理よね。で、この utme だとシルクスクリーンによる量産よりはちょい高いがフルカラーで印刷できて一枚から作れる、納期も短いってことで、良いとこ狙ってるなぁて感じです。品質は知らないけど。

で、私はシンガポールに住んでいるので日本のユニクロに注文しても最終的にブツをこっちに持ってこなくてはいけない。1990円では済まない。なので同じのはこっちにあるかしらねー。去年はTシャツに直接プリンタに出力するようなものはなかった。サブカル大国日本とは勝負になりませんね。と思ったら今年見たらあった。 DTG (Direct to Garment) というらしい。のでメモ。

両方とも発注とかはフォームにちょこちょこ書く系で自動化率は低い。その辺は手作りのコミュニケーションlah。下の方がセンスがいいが高いね。シャツのモノは同じ会社みたい。25SGD でも 2000円なのでまあ一回試してみようかな。

他の会社もあったけど値段が書いていない。ホンマ商売下手よねー

4.02 予習その2 新しい module type、 (module M)

OCaml 4.02 に追加された新しいモジュール型、 (module M) が結構いけているのです。

OCaml である既存のモジュールの型は?というと、 module type of M というのがあって、 module type of Unix とやると Unix モジュールの signature を貰えるというものでした、が、これがあまり使いたいときに使えないものでした。

OCaml で既存モジュールに何か関数を足したいことがあります。特に元から付いている標準のライブラリは足りないものが多すぎる。たとえば Unix.usleep が欲しい:

module Unix = struct
  include Unix
  let usleep x = ignore (select [] [] [] x)
end

はい、簡単にできました。ではこのオレオレ Unix の型を書きたい。これは元の Unix モジュールのシグナチャに usleep を足したものですが、どう書いたらいいだろうか:

module Unix : sig
  (* 何を書いたらいいだろう? *)
  val usleep : float -> unit
  (** [usleep n] sleeps for [n] seconds! Cool! *)
end

unix.mli の内容をコピペするのはあまりに悲しすぎますね、結論から言うと、 include (module Unix) で嬉しい!なのです。

が、 4.02 以前にはこれはなかったんだよね。 3.12.0 で module type of M が入ったとき、おっ、これは module type of Unix と書けばよいのではないか、そう思いました:

module Unix : sig
  include module type of Unix
  val sleep : float -> unit
  (** [usleep n] sleeps for [n] seconds! Cool! *)
end

いやーこれですっきり解決!と思ったら駄目だったんです。なぜかというと元の Unix にある Unix.file_descr とオレオレ Unix にある Unix.file_descr が違う型という扱いになっている。なので、たとえばオレオレ UnixUnix.open した file_descr を元 Unix.read で使う、とかその逆ができません。これは、オレオレライブラリだけで住んでいれば問題ないのですが、いろんな Unix を使うライブラリと組み合わせることができなくなり、つらい。これを解決するには、この二つの file_descr が同じであることを明示してやる必要があります:

module Unix : sig
  include module type of Unix with type file_descr = Unix.file_descr
  val sleep : float -> unit
  (** [usleep n] sleeps for [n] seconds! Cool! *)
end

ああ、なるほど、これで一件落着、かと思いきや、 Unix にあるデータ型は file_descr だけじゃない。 error もあるし process_status もある。これみんな with type t = Unix.t て書かなきゃいけないのです。

クソですね。

なので、オレオレで既存モジュールを拡張したいときはこうしなければいけなかった:

module XUnix : sig
  val sleep : float -> unit
  (** [usleep n] sleeps for [n] seconds! Cool! *)
end = struct
  let usleep x = ignore (select [] [] [] x)
end

module Unix = struct
  include Unix
  include XUnix
end

つまり、拡張部分だけのモジュール XUnix を書いてそこで拡張部分だけに関するシグナチャを書き、元の Unix と拡張 XUnix の統合はシグナチャ書かないでやると。この部分の sig や mli は提供しないが空気を読めよと、そういうわけだ。

で、なんかさっきから頭に引っかかってたんだけど、同じことを三年前に書いてるわけ:

ヤンナルネ…

まあ、これが問題だったんだけど、 (module M) というので解決、というか、なんでまずこれを入れなかったんだ…まあこうやって標準ライブラリをガンガン拡張する立場にあるインダストリィですか、エンタープライズですか、そういう経験のある人がまだ OCaml の内部にやいやい口を出す時代ではなかったのですね…

で、 (module M) というのはモジュール M のシグナチャ。型は元と全部同じ!というナイスなモジュール型なので、

module Unix : sig
  include (module Unix)
  val sleep : float -> unit
  (** [usleep n] sleeps for [n] seconds! Cool! *)
end = struct
  include Unix
  let usleep x = ignore (select [] [] [] x)
end

と書けるようになりました。よかった!

大事なことは全部MLが教えてくれた 〜 Apple の Swift の mutability 周りの件を理解する

開発者アカウントに金が出せない貧乏人の方々が、次の Apple の Swift のコードの挙動がわからない、というので盛り上がっております:

let a = [1,2]          // a = [1,2]
var b = a;             // b = [1,2]
b[1] = 3;              // a = [1,3]  b = [1,3]
b.append(5);           // a = [1,3]  b = [1,3,5]
b[1] = 4;              // a = [1,3]  b = [1,4,5]

もちろんわたしも貧乏ですからわかりやすい炎上案件を待っておるわけです。これはわかりやすいわからないが来たね。

だいたい

  • b[1] = 3 とやると a[1] も変化する、これがわからないという人
  • b[1] = 4 とやると a[1] が変化しない、これがわからないという人

二種類いるようです。私はまず、 b[1] に代入できることがわかりませんでしたのでそれ以前の人間です。

こういうとき、このコードが何をやっているかを理解するには同じ挙動をする ML のコードを書くとわかりやすいです。なぜ ML かというと、もちろんみんなの好きな関数型言語であって、かつ代入などの副作用を持っていて、でも基本は不変データなので可変データの部分はちゃんと明示してやらなきゃいけない言語なので、こういう副作用でわけわからんコードを読み解くには明示する分都合がよろしいからです。もちろんみんなが好きな関数型言語というのはここではとくに意味がありません。Haskell は本題に行く前に Haskell は純粋で純粋なのに副作用があったりなかったりうだうだモナドがああだこうだで圏論があしたどしたでドヤってめんどくさ過ぎるのでこういうのには向きません。

ええっと、断っておきますが、これは上の Apple の Swift コードの挙動と同じ挙動を持つ一番単純な ML のコードって何かしらん、という試みです。オッカムの剃刀の原理を信じれば、そのコードと同じことがおそらく Apple の Swift の中で起こっておるであろう、ということです。実際の Apple の Swift の中がどうなっているかは私貧乏ですから知りません。ただ、まあ ML のコードを見れば、まあ多かれ少なかれ、こんな内部実装なんであろうなあ、と十分推測できるわけです。

そんな手探りせずに仕様書読めという突っ込みもありですがね。まあこういう群貧撫AppleのSwiftみたいな話もたまにはいいんじゃないですか、仕様書探すの難しいらしいし (http://cpplover.blogspot.jp/2014/06/appleswift.html)、どんなプログラミング言語であれ、仕様書を読まないとわからない言語仕様というのはできるだけ少ないに越したことはありません。

で、書くとこんなんになります。 http://try.ocamlpro.com/ で一行づつ入れながら、途中で a;; とか b;; して変化を見ながら試してみるといいよ:

let a = [| 1; 2 |];;
let b = ref a;;                (* 明示的に参照ですって言わないといけないんです *)
!b.(1) <- 3;;                  (* 参照の中身を見るには !b って書かないといけないんです *)
b := Array.append !b [|5|];;   (* 参照先を変えたいときは b := ほげほげ って書くんです *)
!b.(1) <- 4;;                  (* 配列のn番目要素は a.(n) て書くんですキモイ *)
  • b[1] = 3 とやると a[1] が変化するのがわからない人は、 var b = a がコピーは行わないってことをわからない人です
  • b[1] = 4 とやると a[1] が変化しないのがわからない人は、b.append(5) が b 自体を変えてしまうことがわからない人です、ってかこれ普通わかんないでしょ

でもこれ両方とも ML で書いたコードではハッキリわかりますよね。少なくともこの例を見る限りは、

  • var b = e は e の値への参照を作るだけでコピーはしない
  • b.append(5) は参照する値に 5 をくっつける。配列だから結果はコピーになる。 b はそこに参照先を変える

という意味だとわかる。(Array.append はコピーするんですよ。というか配列の後ろに何かつけてもコピーじゃないってそんなすごい配列があったらそれは配列じゃない) copy-on-write とかカッコイイ機能を入れようとしたけどバグっているんだ!とかそういうオシャレ事案ではない。

クソですね。

オブジェクトのメソッド呼び出しのような外見なんだけど、呼ばれた後、オブジェクト自身は他のに摩り替わっている。高度なナリスマシ事案だ。これはヒドイ仕様だと思います。 ML なら b := Array.append !b [|5|] と書くわけなので、 b の参照先が変わっていることがわかる。append すると配列がコピーされるかどうかはもちろん配列というデータ構造の特性を知らないといけないのであれだけど。

せっかくだから Apple の Swift の人の立場になって考えましょう。これはどう直せばいいですかね。

  • var b = e は e の値のコピーを作ってそれを参照することにする

これはパフォーマンス落ちる…のなら、気休めに copy-on-write 導入しますか。 b[1] = 3 とやっても a[1] が変わらない… まあよく判んない人相手にはこの挙動が一番いいのかもしれませんね。

  • 配列を頭よくして b.append(5) とやっても b の中身は成りすましにならず、ちゃんと b[1] = 4 の後 a[1] = 4 になる。

これは配列はもはや配列ではなくて何か別の rope みたいなものになります。うーんそれは配列ではない。

  • b.append(5) などというクソいメソッドはやめて b = b ++ [5] みたいにする。

これならコピーしていることがわかる?かな?いやー無理でしょうねぇ。でも少なくとも現時点での挙動でメソッド呼び出しの形は誤解をまねきやすすぎるよね。

この中でどれが一番いいか…やはり ML を使うことだと思いますね。おわり。

Swift について

普段パクリにはうるさそうな連中が Apple 様がパクルとスルーして嬉しそうにしているので、ああ所詮はそういう人達なんだなあと思って拝見しております。

アイコンまでクリソツなのでもう駄目ですね。

まあ元祖が Hello world の例さえ動かないのはちょっと悲しいですね…

純粋関数型のコンセプトを「関数型言語ではー」とか広げて言わんといて!

そもそも「関数型言語」という言葉自体、どうなんやいうのもあるんですけど http://www.slideshare.net/ksknac/120901fp-key

とある純粋関数型言語の特徴でもって「関数型言語ではー」とか言われると、非純粋関数型言語のユーザーとしては(いやお仕事では純粋関数型言語使ってますけどね)もにょっとしてしまうんですよ

  • 関数型言語は遅延評価だから、すばらしい/クソだ (いやいや純粋関数型言語でも先行評価の言語あるからー、あんたのは違うかもしれんけどよー
  • 関数型言語は副作用が状態がないので、すばらしい/クソだ (いやいやまず純粋関数型の人たちでまず副作用が何指してるか決めてから来てよー
  • 関数型言語はインデントで意味が、型クラスが、、、すばらしい/クソだ

Haskell の話なら Haskell ではーとか、やっぱり GHC だね!とか書いてよ!「アジアではー、ニンジャがゲーシャとハラキリでテンプラ!」みたいなの見たら突っ込まざるを得ないじゃん!純粋アーリア人(問題のある発言)がドイツ語しゃべったら、ワタシ、インドから来たナンディさんネー、はドイツ語しゃべれるのか?ちゃうやろ?

OOPでは多重継承はさまざまな問題が発生するのでジャバーのようにインターフェース以外では許されないほうがいいですよー」とかなら是非はともかくええのよ。

OOPでは多重継承はさまざまな問題が発生するのでインターフェース以外では許されていないんですよー」とか言わないっしょ?

純粋関数型言語だけが関数型言語じゃ、ないんで、、、他のやれとは言わんけど、、、