参考になる
0の0乗
はてなブックマークで、0の0乗についての記事がホットエントリーになっていた。
0の0乗の正解がネット検索しても見つからないので作成した。 | 子育ての達人 | 妊娠・出産・育児・子育ての毎日を楽しく
「いろんな言い分は多々見受けられましたが、正しい解答に言及しているサイト(ページ)は見つからなかった」というが、この記事自体に問題があると感じた。しかし、色々考えたけれども、あまりうまくまとめることができなかった。とりあえず、考えたことを以下にメモとして残しておく。
この記事では、一方で「なぜ2の0乗は1になる」と問うておきながら、マイナス乗については、「定義は定義としてすんなり受け入れなければいけません」と主張している。これはチグハグだ。
定義というのは、そこからの議論を厳密に行うために必要なものだ。数学で議論の対象になるもの(「数学的対象」という)は、無数に存在している。互いに似通った対象が多数存在するわけだから、数学では議論を始める前に定義を行い、どの言葉がどの対象を指しているかを決めておかなければならない。そうして、決めておいた定義や公理から推論して、様々な定理を導き出す。これが純粋に数学な議論だ。
「定義は定義としてすんなり受け入れなければいけません」という話は要するに「数学は定義が与えられて初めて議論が始められる」ということだ。マイナス乗をと定義するように、ゼロ乗もなどと定義して、数学的な議論を始めることができる。
しかし、件の記事の議論は違う。
累乗の説明が終わったので0乗の説明に行きます。ここまで来ると簡単です。
つまり、2の0乗というのは2/2(2÷2)なので1なのです。
例として2で進めましたが2以外の数でも同じです。従って、0の0乗とは、0/0(0÷0)のことです。
明らかに、これは定義から推論して法則を導き出す数学的な証明ではない。指数法則が成り立つように、と定義したいという、定義の動機の話だ。
「なぜ2の0乗は1になるか」「なぜ0の0乗は未定義になるか」という問いは、2通りに解釈できるということでもある。数学で「なぜか」と言ったら、普通は「なぜか、を証明して示せ」ということを意味している。しかし、の定義がないうちには、「を証明せよ」という純粋に数学的な問いは成り立たない。「なぜか」という文のもう1つ、「なぜ数学者は(数学では)が成り立つような定義を採用するのか」を意味するだろう。これは数学者の動機の問題で、純粋に数学的な問題ではないし、コンセンサスも存在しない。
付録: なぜ私はとなるような定義を採用するのか
「定義の理由」にコンセンサスがあるわけではないけれども、「冪乗」と「指数関数」を使い分けて説明すると、理由を納得しやすいと思う。
掛け算の繰り返しで定義されている冪乗には指数法則が成り立つ。一方で、別の方法で定義されている*1指数関数にも、指数法則が成り立つ。が正の整数であるときには指数関数と冪乗は一致し、となる。だから、数学では多くの場合指数関数を冪乗と同じ記法で表しているし、同一視することもある。考えが変わったので、取り消す。11月23日
この説明は、となる理由を説明できるが、高校数学の範囲での指数関数は、底がの範囲でしか定義されていないから、やの定義には、別の説明が必要になる。
定義の理由の理解がどのようであれ、定義自体が共有されているのであれば、数学的な議論を行う上で問題はない。
RDFa Liteのここが酷い
RDFa LiteはRDFa Coreのサブセットで、とても短い仕様なのだけれども、一点気に入らない。
なぜ、@aboutではなく@resourceを採用したのか。
RDFa 1.1 Primerによれば、@aboutと@resourceの違いは、同じ要素に@propertyが設定されている場合の意味の差だけだ。どう違うかというと……
- @aboutは、いつでも関係の主体 (subject) を設定する。
- @resourceは、@propertyが設定されていない場合は@aboutと同様関係の主体を設定する。@propertyが設定されている場合は@hrefと同様関係の客体 (resource object) を設定する。(ただし、hrefと違って、クリックできないリンクになる。)
属性名からも明らかなように、RDFa Coreの@resourceはリソースオブジェクトを設定するのが主用途だ。@propertyが設定されていない場合の意味は、「ついで」で決められていることに過ぎない。*1(これ自体センスがない仕様だ。意味が無い指定であれば未定義として残しておけばいいのであって、無理やり@aboutと同義にする必要がない。)
@resourceの唯一の意義であった「@hrefと違って、クリックできないリンクになる」という性質だって、今日のHTMLの仕様と組み合わせるのであれば、a要素の代わりにlink要素を使えば達成できるのだから、いよいよ@resourceの存在意義は無い。
@aboutを捨てて@resourceの方を選ぶというのは、全くセンスがない。他の属性が設定されているかどうかによって意味が変わる属性とか、ありえない。@propertyと@resourceを同じ要素に設定する“間違い”をしでかす人間は必ず出てくるし、仕様を策定する人間にセンスがないと、全世界に迷惑を掛ける。RDFa 1.1 Primerにその“間違い”を例示するぐらいだったら、最初から@aboutをプライマリとして採用してくださいよ。
schema.org/URLってダメ
(Poor schema.org/URL - Ryusei’s Notes (a.k.a. M59のブログ)の雑な日本語訳。というか、原文が雑な英語すぎるし、まとまってない。)
schema.org/URL というデータ型が定義されているんだけど、これって酷いよね。「この属性のデータ型って何?」「URL。」って、答えになってないじゃん。
URLってのは、単なる識別子だよ。これはURLだなんて分かってる。ウェブにあるモノってのは、だいたいそれを指すURLを持ってる。知りたいのは、それがURLってことじゃなくて、そのURLが指しているモノの型が何なのかってことなんだから。
URLは、schema.org/Textのサブタイプであるべきじゃない。ハイパーリンクとして指定されているURLは、モノがある場所として解釈されるべきで、URLそれ自体がモノとして解釈されるべきではない。
Poor schema.org/URL
schema.org/URL is one of data types defined for linked data. I hate it, because it is totally useless. “Hey, what is the data type of this attribute?” “URL.” That is nonsense.
An URL is just an identifier. That is URL, I know. Almost every thing on the web have an URL that denotes it. What I want to know is the data type of the thing that the URL stands for.
URL should not the subtype of schema.org/Text. The URL specified for a property as hyperlink should be interpreted as the location that the thing is. Not be the URL itself the thing.
ソースコードは基本設計図か
用語ミニ解説として、オープンソースが「基本設計図である「ソースコード」が公に開示されているソフト」と解説されているのだけれども、ソースコードは基本設計図なのだろうか。
基本設計図というのは建築における用語だ。建築では、設計図には基本設計図と実施設計図とがある。建築工事に必要なのは、実施設計図だ。www.homes.co.jp
建築における基本設計図とソフトウェアにおけるソースコードの間には、重大な差異がある。基本設計図の段階ではまだ建物は建てられないのに対して、ソースコードは既にビルドできる状態のもので、ビルドすれば実働するソフトウェアが得られるという点だ。建築にたとえるなら、ソースコードはすでに「建築工事」に回せる段階のものだから、これはむしろ「実施設計図」に相当する。
コメント欄についてのコメントまとめ
Twitterのツイートをまとめました。
2012年
コメント欄に載っけるか載っけないかで揉めるし、もうコメント欄は無くしちゃってコメントはツイッターにでも書かせてしまうのがいいのかもなー
— Ryusei Yamaguchi (@mandel59) 2012, 8月 17
ブログからはコメント欄を取ってしまったのだけれども、これは「文句言うな」じゃなくて、はてブでもTwitterでもどこでもいいから、もっと色々な場所でコメントして欲しいってことです。Request for Commentsです。面白い意見を聞かせてください。
— Ryusei Yamaguchi (@mandel59) 2012, 9月 25
2014年1月17日
NATROMの日記のコメント欄が承認制になった時のコメントです。
“執拗な発言者の存在のためコメントを承認制にします - NATROMの日記” http://t.co/wzAiYo0iks
他63コメント http://t.co/pmmYaAn57T
— Ryusei Yamaguchi (@mandel59) 2014, 1月 27
http://t.co/mCSDwPHFNs
「コメント承認制のデメリットが一つ明らかになりました。」
「コメントを読む際、あるいはコメントを書き込む際には、読者の皆さんはこのような現象が起こりうるということを念頭に置いてくだされば幸いです。」
そんなこと言われたってしょうがない
— Ryusei Yamaguchi (@mandel59) 2014, 1月 27
コメント欄の何が面倒かって、他人の発言を自分が管理しなきゃいけないところ。承認制にするともっと面倒で、他人の発言を自分が「承認」したという事実で、他人の発言への責任をもっと持たないといけなくなる。承認制の時点で自由な議論もできないし、だったら廃止しちゃった方がずっと楽だ。
— Ryusei Yamaguchi (@mandel59) 2014, 1月 27
コメント欄が無くてもみんな勝手にTwitterだったりはてブだとかに書くわけで、なんの問題もない。
— Ryusei Yamaguchi (@mandel59) 2014, 1月 27
例えばOSASKも、Wikiというシステムを使いながら、勝手に書きかえてはいけないなど独自のガイドラインを設けるって形で運用していたけどうまくいかなかった。ガイドラインはWikipediaにもあるけど、やっぱりうまくいってるわけじゃないよね。結局半凍結とかするしかない。
— Ryusei Yamaguchi (@mandel59) 2014, 1月 27
人間が文化的になることによって問題を解決しようという「文化的な解決」は、Wikiだとかコメント欄だとか掲示板のような大衆に開放されたコミュニティでは必ずしもうまくいかなくて、何らかのアクセス管理が必要になってしまう。
— Ryusei Yamaguchi (@mandel59) 2014, 1月 27
つまり荒らしは管理者がBANしないといけない。
— Ryusei Yamaguchi (@mandel59) 2014, 1月 27
もちろん、2ちゃんねるみたいに管理者の存在が薄いような場所だったら「荒らしはスルー推奨」のような「文化的な対応」で対処するしかない。
— Ryusei Yamaguchi (@mandel59) 2014, 1月 27
コメント欄、本当は記事に対するコメントを書く場所であるのが理想なのに、コメントに対するコメントが付くことは避けられなくて、そうすると記事の話題とはどんどん離れていってしまうことになるし。
— Ryusei Yamaguchi (@mandel59) 2014, 1月 27
はてなダイアリーのコメント欄はコメントに対するコメントをぶら下げることができるようになっていないので、全部のコメントがひとつのスレッドにぶら下がることになってしまう。
— Ryusei Yamaguchi (@mandel59) 2014, 1月 27
スレッドがひとつだけだということは強制的にひとつの話題に集中させる効果はあると思うが、その話題が元の記事から離れていってしまうのはよくないと思う。
— Ryusei Yamaguchi (@mandel59) 2014, 1月 27
2015年1月6日
Qiitaというウェブサイトのコメント欄が荒れた時のコメントです。
コメント欄って、チャットスペースじゃないけど、コメントへのコメントがしたくなるって点で悪い設計だと思うし、メタコメントができないコメント欄は撤去してしまった方がずっといいと思う
— Ryusei Yamaguchi (@mandel59) 2015, 1月 6
2015年7月28日
またQiitaのコメント欄が荒れていました。その時のコメントです。
荒らしや自演がおこるの、コメント欄があるからってのもあるし、Qiitaはコメント欄全廃すればいいのでは
— Ryusei Yamaguchi (@mandel59) 2015, 7月 28
基本的に「コメント欄」という仕組みは、ページの管理者以外がコンテンツをいじることができるという仕組みで、必ずしも優れているわけではない。
— Ryusei Yamaguchi (@mandel59) 2015, 7月 28
本記事へのコメントではなく、コメントへのコメントのためのコメント欄になってしまっては、コメント欄の意義がよく分からなくなってしまうし、ひとつの記事にひとりがコメントできるのは一件だけ、のような制限が必要。
— Ryusei Yamaguchi (@mandel59) 2015, 7月 28
僕のブログではコメント欄は廃止してしまっていて、コメントははてブとかで勝手に付けてねってスタンスを取っている。
— Ryusei Yamaguchi (@mandel59) 2015, 7月 28
本記事へのコメントとコメントへのコメントを区別する仕組みと、コメントの量を制限する仕組みがないから、荒れてしまう。
— Ryusei Yamaguchi (@mandel59) 2015, 7月 28
まあシステムが悪くてどうしようもないところ、匿名掲示板では「荒らしに対してはスルー推奨」という対処の知恵が生まれてきたりしたわけなんですけど、その基本ができてない人多すぎですね。
— Ryusei Yamaguchi (@mandel59) 2015, 7月 28
2015年8月5日
コメント欄について議論する分野はどこなのかについての疑問です。
ユーザーインターフェイスは人間と関係する部分だけど、例えばウェブサービスのあり方について、ユーザーインターフェースよりも高次の視点からの批評方法とか、身につけたいじゃないですか。
— Ryusei Yamaguchi (@mandel59) 2015, 8月 4
ブログにコメント欄は必要なの? とか、色々面白そうなテーマがあると思うんだけど、どうも情報科学の範疇からはずれてしまう。
— Ryusei Yamaguchi (@mandel59) 2015, 8月 4
それはやっぱり社会情報学の範疇に入っていっちゃうのかなー
— Ryusei Yamaguchi (@mandel59) 2015, 8月 4
望ましいコメント欄の姿はなんだろう。
この記事は、イケダハヤト氏の記事に反応して書かれたものだ。コメント欄について、私は過去にもいくらか考えてきた。Twilogからコメント欄についてのコメントを拾い、あらためて自分の意見を確認した。
この記事ではコメント欄を閉鎖する理由を「ゴミの掃き溜めです」、「建設的ではありません」と、説明している。一方で、「サイトコンテンツを拡充するという観点では、コメント欄は本来的には有意義」とも書いている。前者は、コメント欄につくコメントは無価値であると言っていて、しかし、後者はコメント欄が本来的に有価値であることを訴えている。
私もブログのコメント欄は閉鎖したほうがよい場合があると考えているが、それはコメント欄にゴミのようなコメントしか付かないから、議論が建設的でないから、といった理由ではない。だいたい「ゴミのような」だとか「建設的でない」のような判断は主観的な価値判断に過ぎないもので、ゴミのようなコメントが付いたり、建設的でない議論が繰り返されること自体から、何らかの意味を見出すこともできる。ゴミのようなコメントが付くコメント欄は十分有意義で、ただ記事の著者にとっては不都合・不愉快である場合があるというだけだ。
私が撤去したほうが良いと考えるコメント欄には、個々のコメントの管理の問題と、話題の管理の問題がある。
個々のコメント管理の問題というのは、社会的に問題のある発言を削除しなければならないということだ。もしコメント欄の管理を記事の著者自身で行っていると、コメント投稿者に、記事の著者にとって都合の悪い発言や反論が不当に削除・検閲されているのではないかという疑念を抱かせてしまう。最初から外部のサービスにコメント管理を委譲してしまい、著者自身で管理できないようにしてしまえば、著者は他人のコメントに何ら責任を負う必要がなく、とても気楽だ。
話題の管理の問題というのは、コメント欄が荒れることだ。はてなブログのコメント欄のように、コメントが一列のリストになっている場合、コメント欄の荒れが問題になりやすく、荒らしに脆弱だ。コメント欄が荒れて機能不全を起こすのは「記事に対するコメント」と「コメントに対するコメント」が区別されていないからで、スラドのようにツリー構造のコメント欄であれば、ツリーごとに異なる話題を続けられるから、ひとつの枝が荒れていても、他の枝に影響しづらい。あるいは、ツイッターのように、コメントどうしが勝手に参照しあうような構造でもよい。ツイッターのような構造は議論には向かなくなり、よりコメントらしい使い方になる。はてブのように、コメント量を制限しても、荒れることはない。
そういうわけで、撤去せずとも良いコメント欄は次の性質を持つ。
- 著者自身が管理できない。個別のコメントの削除はコメントした人自身か、コメントサービス提供者が行う。記事の著者が他人のコメントに責任を負ってはいけない。
- コメント欄の話題が1つにロックされない。複数の話題を持てるツリー型や、話題が存在しないツイート収集型、コメント量を制限するブックマークコメント型などにする。
Facebookコメント、Twitterの検索結果タイムライン、そしてこのブログにあるような、はてブコメント欄のどれも、この性質を満たしている。あとはコメント欄をブログに埋め込むかどうかは個々人の“衛生観念”の差で決まるもので、自分に対して批判的なコメントを読むのは精神に悪いからコメント欄を設置しないというのも、別にいいのではないかと思う。
CSSでヒラギノ角ゴシックのウェイトを指定する方法
※追記あります
Mac OS X El Capitanのヒラギノ角ゴシック — Medium
ヒラギノ角ゴシックは10ウェイトあるが、CSSでは9つ(100から900まで100間隔)でしか指定できない。しかも、具体的にどのウェイトで表示されるかが、ブラウザによって異なっているようだ。
font-weight
と実際に使われるウェイトの対応の表:
CSS font-weight | Firefox | Chrome |
---|---|---|
100 | W0 | W0 |
200 | W2 | W1 |
300 | W3 | W3 |
400 | W4 | W4 |
500 | W5 | W5 |
600 | W6 | W6 |
700 | W7 | W7 |
800 | W8 | W8 |
900 | W9 | W9 |
また、normalとboldはそれぞれ400と700を指定するのと同じなのだが、今までのヒラギノ角ゴではW3とW6を使ってきたのだから、これでは少し太いかもしれない。こういう時は、@font-face
を使って、ウェイトと実際に使われるフォントの関係を直接指定してしまえばいい。
@font-face { font-family: "Hiragino Sans"; src: local(HiraginoSans-W0); font-weight: 100; } @font-face { font-family: "Hiragino Sans"; src: local(HiraginoSans-W1); font-weight: 200; } @font-face { font-family: "Hiragino Sans"; src: local(HiraginoSans-W2); font-weight: 300; } @font-face { font-family: "Hiragino Sans"; src: local(HiraginoSans-W3); font-weight: 400; } @font-face { font-family: "Hiragino Sans"; src: local(HiraginoSans-W4); font-weight: 500; } @font-face { font-family: "Hiragino Sans"; src: local(HiraginoSans-W5); font-weight: 600; } @font-face { font-family: "Hiragino Sans"; src: local(HiraginoSans-W6); font-weight: 700; } @font-face { font-family: "Hiragino Sans"; src: local(HiraginoSans-W7); font-weight: 800; } @font-face { font-family: "Hiragino Sans"; src: local(HiraginoSans-W8); font-weight: 900; } @font-face { font-family: "Hiragino Sans W9"; src: local(HiraginoSans-W9); font-weight: 900; } div { font-family: "Hiragino Sans"; font-size: 20pt; line-height: 1.5em; }
<div style="font-weight: 100">ヒラギノ角ゴシック W0</div> <div style="font-weight: 200">ヒラギノ角ゴシック W1</div> <div style="font-weight: 300">ヒラギノ角ゴシック W2</div> <div style="font-weight: 400">ヒラギノ角ゴシック W3</div> <div style="font-weight: 500">ヒラギノ角ゴシック W4</div> <div style="font-weight: 600">ヒラギノ角ゴシック W5</div> <div style="font-weight: 700">ヒラギノ角ゴシック W6</div> <div style="font-weight: 800">ヒラギノ角ゴシック W7</div> <div style="font-weight: 900">ヒラギノ角ゴシック W8</div> <div style="font-family: 'Hiragino Sans W9'">ヒラギノ角ゴシック W9</div>
10月4日追記
上の方法だと、Firefoxでは正しく表示されるが、SafariやGoogle Chromeだと、W5が正しく表示されない。
Safariでの表示
本来boldでないW5にfont-weight: 600
を指定していると、機械的にboldになってしまうようだ。
やはりfont-weightを使わず、直接指定するのが無難だろう。
GMailのリプライをスレッドにまとめる機能は完全にダメ
GMailのアプリは関連するメールを一つにまとめる機能があるけど、この仕様を把握していないせいで完全に失敗した。メールに新規の未読のリプライが付いても、それは既読のメールの下に表示されるわけで、これじゃあ未読のリプライの内容を読み逃してしまうに決まっているじゃないか。なんでこんな仕様なんだ。
https://support.google.com/mail/answer/5900?hl=ja
■
人力検索はてなの質問をキャンセルしたら内容が消えてしまったので、こちらに残しておく。
昔読んだ数学の児童書を探しています。 内容は断片的にしか覚えていません。おそらく12年以上前に図書館で読んだ本です。 小説仕立ての本であり、ワープロのフロッピーディスクに、奇妙な外字で書かれた文書が保存されていて、それはコンピューターに住む未知の生命体の残した、未知の数学に関するメッセージだったというような話だったように思います。いくつかのトピックがあったと思いますが、そのひとつとして、p進数(p-adic number)に関連するようなトピックがありました。もしかしたら、大きめの判型の本で、上下で2冊分の本だったかもしれませんが、確かではありません。 少ない情報ですが、心当たりがあるかたはよろしくお願いします。
http://q.hatena.ne.jp/1443281726
@mandel59 大森英樹先生の本ではないでしょうか。 http://t.co/CdMKvPGUmJ
— koji hasegawa (@myfavoritescene) 2015, 9月 26
ありがとうございました。
関数とラムダ計算の話
この記事へのツッコミみたいなことを書くつもりだったけど、あんまり関係ない話になったので、サイドストーリーみたいにして読んでください。
分野によって「関数」が違うこともある
前回、数学的な関数の定義の話があったけど、あれは写像の定義であって、個々の分野で「関数」と呼ばれているものと、いつでも一致するとは限らない。まあ普通は関数と言ったらほとんどの場合写像を指すので、少し違う物を指すときは、多価関数とか連続関数みたいに、別の名前を付けていることも多い。
で、プログラミングに関する文脈で「関数」と呼ばれるものが写像と一致するかといえば、もちろん一致しない。ある程度似た部分もあるけど、違う性質を持っている。この違いを、数学的にどうやって説明するかが問題になる。計算の性質を説明するための抽象モデルが抽象書換系で、ラムダ計算の意味も、抽象書換系によって定義できる。この定義の方法は、写像の定義とは大きく異なっている。
写像とラムダ項の間には、具体的にどういう違うがあるのだろうか。
- 写像はドメイン(始域)とコドメイン(終域)が定義されている。一方、ラムダ計算におけるラムダ項に、ドメインやコドメインといった考えはない。
- 写像は全域性を持つ。つまり、どのようなに対しても、は必ず値を持つ。一方、ラムダ計算には正規形を持たない元がある。それは、の計算が停止しない場合に対応する。
一方で、写像には右一意性という性質があるが、ラムダ計算には合流性という性質があり、計算が停止する範囲では、写像とよく似た性質を持っているということが言える。
アクションと関数、式の値の話
a -> b
というのは、引数にa
型の値をとり、b
型の値を返す関数の型だ。Monad m
が存在するような任意の型コンストラクタm
について、m a
というのは、a
型の値を生成する(Monad m
の)アクションの型だ。
という型の意味を理解していれば、関数(>>) :: Monad m => m a -> m b -> m b
は、その型から、
Monad m
が存在するような任意の型コンストラクタm
について、m a
型の値(アクション)(これをx
とする)を引数にとり、m b -> m b
型の値(関数)(これは(>>) x
と表せる)を返す関数で、つまりその返される関数は、m b
型の値(アクション)(これをy
とする)を引数にとり、m b
型の値(アクション)(これは(>>) x y
と表せる)を返す関数で、つまりその返されるアクションは、b
型の値を生成するアクション
だということが読み取れる。
一方で、「m a
型の値(アクション)x
を破棄する」といったことは、型から読み取ることはできないし、事実でもない。実際、(>>) x y = (>>=) x (\z -> y)
と定義でき、アクションx
は破棄されない。破棄されるのはアクションx
が生成する値で、それはx
ではなくz
だ。
関数が値を返すということと、アクションが値を生成するということには大差がないように見える。実際に、多くのプログラミング言語は関数に副作用を認めていて、関数とアクションを区別しない。しかし、関数が、引数が定まれば返り値も一意に定まるという性質を持っているのに対し、アクションは、生成する値が定まるという性質を持っていないから、同列に扱おうとすると、式の値が一意に決まらなくなる、という困ったことが起きる。
そもそも、式の値はなんだろうか。(ここで書いている「手続き型プログラミング」「関数型プログラミング」という分け方は一面的なものに過ぎないから、あんまり深刻に考えないで欲しいのだけれども、)手続き型プログラミングにおいて、値というのは手続きから手続きへ渡されたり、変数に代入されたり読み出されたりするものであって、「式が値を持つ」という考えは、算術の式に対しては考えていても、プログラム一般に敷衍されるものではないように思われる。プログラムは文の集合だ。文は意味を持つが値を持たない。それが、手続き的なプログラミングにおいて一般的な考え方だ。
一方、関数型プログラミングでは、プログラムは式だ。関数型プログラミング言語の式は部分式と関数適用から構成されていて、どの部分式も値を持つ。関数型プログラミングでは、プログラムの構造を内包した値を扱うことでプログラミングするようになる。直和型の値は分岐構造を内包しているし、リスト型の値は反復構造を内包している。モナドは、手続き型言語における各種副作用を持つ、逐次構造を内包した型の集まり(型クラス)ということになる。このように複雑な値を使うことで、関数型プログラミングではプログラムの意味と式の値を同一視できるようになる。
プログラムの意味と式の値を同一視できると何が嬉しいかというと、意味を持つプログラムの断片がすべて値を持つので、プログラムを処理するプログラムが書きやすくなる。プログラムのどの断片も、関数として抽象化することができる。他の関数に渡すことが出来る。変数にプログラムを代入できる。
話をアクションに戻す。Haskellにおいては、アクションが生成する値と、アクション自体は別だ。たとえば、getChar :: IO Char
は標準入力から文字を1文字読み込み、その文字に対応するChar
型の値を生成するアクションなのだけれども、Haskellでは、式getChar
の値は「標準入力から文字を1文字読み込み、その文字に対応するChar
型の値を生成するアクション」自体であり、生成されたChar
型の値ではない。アクションgetChar
の生成する値を取り出して言及するには、do {z <- getChar; k z}
のz
、getChar >>= \z -> k z
のz
とでも言うしかない。
色々書いたけど、結局、値とは何かという話に合意が得られていない状況ではどうにも話が通じないという点が問題で、以前からココらへんの考え方を整理して参照透過性についてなんとか説明しようと試みたりしているのだけれども、やっぱり難しいですね。
ES6のジェネレータはHaskellのdo記法ほど強力ではないという話
この記事では、ES6のジェネレータを使って、Haskellのdo記法を模倣したdoM
関数を定義し、ジェネレータを使ってモナドを取り扱えることを示している。しかし “The same routine can be used with other monads like the Continuation monad” という記述に反し、実はdoM
と一緒に使えるモナドと、使えないモナドがある。
話を簡単にするため、以下ではECMAScriptのプロトタイプチェーン機能を使わないでプログラムを書くことにし、doM
には、モナドを表現するオブジェクトを、引数として別途渡すことにする。
function doM(m, gen) { function step(x) { var y = gen.next(x); if (y.done) { return y.value; } return m.bind(y.value, step); } return step(); }
具体的に、ふたつのモナドOM
とGM
を定義する。OM
はOptionMonadの略で、GM
はGeneratorMonadの略だ。
var OM = { unit: function(x) { return {tag: "Some", value: x}; }, bind: function(n, k) { if (n.tag === "None") { return {tag: "None"}; } return k(n.value); }, }; var GM = { unit: function*(x) { yield x; }, bind: function*(g, k) { for (var i of g) { yield* k(i); } }, };
このとき、OM
に対してはdoM
を適用できる。
var x = doM(OM, function*() { var a = yield OM.unit(2); var b = yield OM.unit(3); return OM.unit(a * b); }()); console.log(x); // ==> Object { tag: "Some", value: 6 } var y = doM(OM, function*() { var a = yield OM.unit(2); var b = yield {tag: "None"}; return OM.unit(a * b); }()); console.log(y); // ==> Object { tag: "None" }
一方で、GM
に対してdoM
を使うと、例外が出てしまう。
var z = doM(GM, function*() { var a = yield function*(){ yield 2; yield 3; yield 4; }(); var b = yield function*(){ yield 5; yield 6; }(); return GeneratorMonad.unit(a * b); }()); try { for(var i of z) { console.log(i); } } catch (e) { console.log(e); // ==> TypeError: k(...) is undefined }
なぜかといえば、GM.bind
は第2引数k
を複数回呼び出す可能性があるからで、一方、doM
内で定義されている関数step
は、ジェネレータの呼出しに副作用を使うことを前提としていて、複数回呼び出されることを考慮しない作りになっているという点が問題となっている。この問題を修正するには、途中まで実行したジェネレータを複製することができる必要があるが、ES6のジェネレータにそのような機能はないようなので、結局ジェネレータを使ってどのようなモナドにも対応したdoM
を実装することはできないということになる。
比較用に、doM
を使わない場合のコードも載せておく。
var w = GM.bind(function*(){ yield 2; yield 3; yield 4; }(), a => GM.bind(function*(){ yield 5; yield 6; }(), b => GM.unit(a * b))); for(var i of w) { console.log(i); }
「抽象化」を抽象化する 〜 nopは確かに抽象化のひとつの形であるという話のメモ書き
さて、以上の議論を踏まえた上で、「世界一抽象化されたコード」というのを今から書いてみましょう。一瞬でかけます。
# nop
上にあげたものがそうです。つまり、「なにもしない」というコードこそが、世界一抽象化されたコードです。
http://nekogata.hatenablog.com/entry/2015/08/05/001742
これが本当に抽象なのか? と疑問に思う人がいるのだけれども、これは確かに一種の抽象化ではあるのだ。これが抽象化だと思えないのは、このnopの例自体が、具体的にどういう抽象化を前提としているかを明示していない、抽象的な例だからだ。「抽象化」という概念それ自体が抽象的だ。関数は、機械に扱える抽象化の機構のひとつなのだけれども、だからといって関数だけが抽象化ではない。
抽象化というのは、プログラムを書くのに使える概念であるという以前に、物の考え方としての概念だという側面がある。このnopの例は、少なくとも、もはやRubyが形式化しているレベルの抽象を越えてしまっていて、それは計算機にとっては意味を持たない(具体的に計算できない)抽象化だ。Ruby処理系に# nop
というコード自体を渡しても、これはコメントを含む空のプログラムだと具体的に解釈されるだけであって、全く抽象性を持たない。だけど、そういう、機械にとって意味を持たない抽象化でも、人間にとっては意味のある何かを抽象している場合がある。コメント行自体もそうだし、アルゴリズムの本などが載せている擬似コードなどは、機械が読めずとも人間が読める、抽象的なコードだ。その抽象的なコードは、人間が適宜解釈し、具体的なプログラミング言語で実装することができる。
条件分岐if C then A else B
を抽象化して、非決定性の分岐A ⊕ B
として考える、といった話と似ている。(抽象化というより、近似と言ったほうがいいのかもしれないけど。あるいは、抽象化というのは、別の視点を変えれば、近似と見ることができる。)
普通プログラマが抽象化と言ったら、機械が扱える範囲での抽象化だけ考えているんだ、と言うかもしれないけど、どういう種類の抽象化を機械が扱えるかというのは、曖昧だ。擬似コードだって、十分に形式化されていれば、処理系を実装して実行することができる。
まとまらないけど、メモ書きだからこれで終わり。