いものやま。

雑多な知識の寄せ集め

『数学ガールの秘密ノート/ビットとバイナリー』を読んでみた。

結城浩先生の新刊、『数学ガールの秘密ノート/ビットとバイナリー』をさっそく読んでみたので、感想など。

概要

数学ガール』シリーズでは、主人公の「僕」と、彼を取り巻く女の子たちによる数学トークが語られている。
クールで数学が得意なミルカさん、元気で数学の疑問にしっかりと向き合っていくテトラちゃんなど、キャラクターも魅力的。

数学ガール』シリーズの中でも、今回読んだ『秘密のノート』シリーズは難易度がやさしめになっていて、中学生から楽しめるものになっている。
今回テーマとして取り上げられたのは、「ビットとバイナリー」ということで、2進数やその周りの数学。
コンピュータ関連というということで、赤髪のコンピュータ好き少女、リサも再登場している。

内容は2進数のおさらいから始まり、ビット操作の話、さらにはブール代数にまで及んでいる。

ビット操作に関しては、画像をスキャナで読み込んでプリンタに出力する、というテーマで話を展開させていて、とても面白かった。
そういうテーマにすると、ビット操作を画像のフィルタ処理と結びつけて話すことが出来るのか・・・

フリップ・トリップとルーラー関数

そんな中でも、個人的にすごく面白かったのが、「フリップ・トリップ」という問題。

フリップ・トリップ N Nは正の整数)は、以下のような問題:

盤面に N個の石(表が白、裏が黒)が並べられている。
石には 0, 1, \ldots , (N-1)と番号がついている。
石に対応して、 0, 1, \ldots , (N-1)と番号のついた反転ボタンがあり、ボタンを押すと対応する石の表裏が入れ替わる。
開始時に石はすべて表(白)になっていて、反転ボタンを押していくことで、同じパターンを出すことなく全てのパターンを出し切るには、どうすればいいか。

具体的な例を見た方が分かりやすそう:

例えば、フリップ・トリップ2なら、以下のような感じ:

init
    0: W [ ]
    1: W [ ]

turn0
    0: W [X]
    1: W [ ]

turn1
    0: B [ ]
    1: W [X]

turn2
    0: B [X]
    1: B [ ]

turn3 <done>
    0: W [ ]
    1: B [ ]

Wは白、Bは黒、[X]はそのボタンを押したということ。

フリップ・トリップ3だと、以下のような感じ:

init
    0: W [ ]
    1: W [ ]
    2: W [ ]

turn0
    0: W [X]
    1: W [ ]
    2: W [ ]

turn1
    0: B [ ]
    1: W [X]
    2: W [ ]

turn2
    0: B [X]
    1: B [ ]
    2: W [ ]

turn3
    0: W [ ]
    1: B [ ]
    2: W [X]

turn4
    0: W [X]
    1: B [ ]
    2: B [ ]

turn5
    0: B [ ]
    1: B [X]
    2: B [ ]

turn6
    0: B [X]
    1: W [ ]
    2: B [ ]

turn7 <done>
    0: W [ ]
    1: W [ ]
    2: B [ ]

この問題を解くために使われるのが、ルーラー関数
「ルーラー」というのは、「定規」という意味。

どうやってルーラー関数を使うのかや、ルーラー関数に関連する話は面白いので、ぜひ本で読んでみてほしい。

超立方体

ところで、この「フリップ・トリップ」問題を読んで自分がまず思ったのは、超立方体の頂点を辺に沿って全部周ればいいんだろうなぁ、ということ。
エピローグで軽く触れられてるんだけど、明示的には書かれていなかったので、ちょっと書いておきたい。

まず、2進数の0と1を頂点において辺でつなぐと、こんな線分になる:

f:id:yamaimo0625:20190731155332p:plain

フリップ・トリップの「白」を「0」、「黒」を「1」と考えると、この頂点はフリップ・トリップ1で出てくるすべてのパターンに対応し、辺は反転ボタン0を押した時の状態変化に対応している:

f:id:yamaimo0625:20190731160034p:plain

なので、フリップ・トリップ1で「1. 初期が白」「2. 反転ボタン0を押す」「3. 黒になる」というのは、この図で以下のように解釈できる:

f:id:yamaimo0625:20190731161059p:plain

これは一次元だったけど、これを横に引き伸ばすと二次元になり、フリップ・トリップ2に対応することになる:

f:id:yamaimo0625:20190731162611p:plain

以下のように辺に沿って移動していく(=反転ボタンを押していく)ことで、すべての頂点(=パターン)を巡っていくことが出来る:

f:id:yamaimo0625:20190731163358p:plain

これをさらに奥に引き伸ばせば三次元になり、フリップ・トリップ3に対応し、以下のように辺を辿っていくと、すべての頂点を巡れる:

f:id:yamaimo0625:20190731165936p:plain

同様に引き伸ばしていくことで、四次元、五次元、さらには N次元と考えていくことが出来る。
四次元についてはエピローグにも出てたり。

そして、このような引き伸ばして作っていった図形を、超立方体と言う。

そして、これまでの例を見てもらえば分かる通り、超立方体の辺に沿ってすべての頂点を巡るというのが、フリップ・トリップ問題の解答に対応している。

ハッセ図

ちなみに、この超立方体、見方を少し変えてみると、面白いことが見えてくる。

まず、一次元。

f:id:yamaimo0625:20190731173356p:plain

次に二次元。

f:id:yamaimo0625:20190731173416p:plain

そして、三次元。

f:id:yamaimo0625:20190731175045p:plain

そう、超立方体は、半順序関係を図示したハッセ図になっている!

ハッセ図については本を読んでほしいんだけど、本でハッセ図が出てきたので、「おぉ、ここから超立方体に繋げて、超立方体の頂点を巡るという話にするのかな?」と思ったら、そうじゃなかった(^^;
このあたりの繋がりについても言及があると、もっとよかったなぁ。

何はともあれ、非常に面白かったので、オススメ!

今日はここまで!

技術書同人誌博覧会に行ってきた。

7/27(土)に、蒲田の大田区産業プラザPiOで開催された「技術書同人誌博覧会」、通称「技書博」に一般参加で行ってきたので、感想など。

第二回技術書同人誌博覧会のお知らせ | 技術書同人誌博覧会

f:id:yamaimo0625:20190728171537p:plain

技書博

「技書博」は、簡単に言ってしまえば、技術書オンリー同人誌即売会

技術書オンリーの同人誌即売会だと、技術書典が有名だけど、技書博はそれとはまた違ったイベント。

ちなみに、次の技術書典7(9/22)にサークル「いもあらい。」として参加するので、よろしくお願いします。
ポーカー(テキサス・ホールデム)を数学的に考えていく本を出す予定です。

今回は初回ということもあり、規模も小さい感じだった。
参加サークル数としては、66サークル。
(※技術書典6は463サークル)

けど、後発ということもあり、いろいろ工夫が見られた。

入場チケット

興味深かったのが、入場チケットをPassMarketを使って用意していたこと。

チケット自体は無料なんだけど、入場を開始できる時間が何種類かに分かれていて、それぞれに上限が設けられている。
なので、流量のコントロールが確実に出来るようになっている。

技術書典では、チケットを有料化することによって、早い時間帯の流量を減らすように促していたけど、流量に上限は設けていなかった。
だから、チケットを買って入っても、混んでるかどうかはどれだけのチケットが出てるか次第。
また、チケットを入手しても、何時に入れるかの確証は得られないという問題があった。
(チケットを購入しても普通に待機列に並ぶことにはなる)

けど、技書博の方法だと、上限がしっかりと決められているので、混雑のコントロールが確実に出来るし、入場で長く待たされるということもなくて、とてもいいと思った。

実際、会場内は程よい人だかりで、快適の一言。
ゆったりと見て回れたので、すごくよかった。

サークルさんからしても、流量がコントロールされるので、忙しさが均等化されたんじゃないかな。

ノベルティ

ノベルティで個人的に嬉しかったのは、お水
水分、重要だからね・・・

あと、カタログも無料で配られてた。
サークルカットにとどまらず、運営側やスポンサーも記事を結構載せてて、結構な厚さがあったのは驚き。

入場も無料だし、ノベルティも恒例の袋に、カタログ・お水、それにうちわもついてて、だいぶスポンサーからお金を出してもらったのかなぁ。
(その分、広告もしっかり入ってて、Win-Winになってるのがとてもいい感じ)

机の配置

机の配置も、実は工夫されてたんじゃないかと思う。

技術書典だと、動線の両脇にサークルが並ぶ感じになっていて、つまり島の長さが非常に長いんだけど、技書博では出来るだけ島を短くしていた
これによって何が嬉しいのかというと、移動のための列とサークルに並ぶための列が分離するということ。

図で見てみると分かりやすい。

まずは技術書典のように、島が長いレイアウト:

f:id:yamaimo0625:20190728193612p:plain

見ての通り、移動のための列(赤)とサークルに並ぶための列(緑)が同じ空間になっている。
なので、混雑しやすい。

一方、技書博のレイアウトは、以下のように島が短くなっていた:

f:id:yamaimo0625:20190728193752p:plain

移動のための列(赤)とサークルに並ぶための列(緑)は分離しているので、混雑しにくい。
島の中を移動するための列(青)はサークルに並ぶための列(緑)と同じ空間になっているので、そこで混雑は発生する可能性があるけれど、島の中を移動するための列(青)は移動のための列(赤)よりずっと短くなっているので、ダメージが少ない。
また、混雑も分散される。

もちろん、使えるスペースは技書博のレイアウトの方が少なくなると思うけど、技術書典も技書博のようなレイアウトをちょっと検討してほしいな。


ちなみに、第2回も予定されてるみたい。

f:id:yamaimo0625:20190728171559p:plain

100サークル以上募集するっぽいので、成長が楽しみ。

今日はここまで!

MacBook Airでマウスを使いやすくしてみた。

f:id:yamaimo0625:20190715142700j:plain

MacBook Airトラックパッドは最高なんだけど、ちょっと困ったことが。
それは何かというと・・・指が痛くなる

もちろん、短い時間使うだけなら問題ないのだけど、長時間使っていると、少しずつダメージが蓄積されていって、ちょっと無視できない痛みに。

この痛みを改善しようと、マウスを併用するようにしてみた。
ただ、そのまま使うと、かなり使いにくい・・・

そこで、ツールを導入して、MacBook Airでマウスを使いやすくしてみた。


ちなみに、Macでのキー配置の調整などについては、以下を参照:

問題点

MacBook Airでマウスを使うと出てくる問題点が、以下の2つ:

  • マウスホイールによるスクロールが普通と逆
  • マウスホイールによるスクロールがキビキビ反応しない

「スクロールが普通と逆」問題

まず、前者について。

マウスホイールを転がすと、普通は以下のようになる:

ホイールを転がす方向 スクロールする方向

これが、MacBook Airだと、以下のようになる:

ホイールを転がす方向 スクロールする方向

これがかなり使いにくい・・・

実はこれ、設定によるもので、トラックパッドの動きに合うようになっている:

トラックパッドをなぞる方向 スクロールする方向

トラックパッドの場合、これがかなり自然な設定になっている。
下になぞれば対象が下に移動し、つまり、画面としては上にスクロールするし、逆もまた然り。

けど、マウスも同じ動きをされてしまっては、困る。

一応、「システム環境設定」-「マウス」-「スクロールの方向:ナチュラル」のチェックを外すと、普通と同じマウスホイールの挙動をするようになる。
ただし、その場合、「システム環境設定」-「トラックパッド」-「スクロールとズーム」-「スクロールの方向:ナチュラル」のチェックも外れてしまい、今度はトラックパッドの挙動がおかしなことになる。

なんで独立して設定できるようにしてないんだろう・・・

なので、以下のような調整をする必要がある:

  • マウスホイールは、
    • 下に転がせば、下にスクロールする
    • 上に転がせば、上にスクロールする
  • トラックパッドは、
    • 下になぞれば、上にスクロールする
    • 上になぞれば、下にスクロールする

「スクロールがキビキビ反応しない」問題

続いて、後者について。

マウスホイールを転がすと、普通は即座に反応して、画面がスクロールする。
けど、MacBook Airだと、なぜかある程度の勢いでホイールを転がさないと、反応しない

これもかなり使いにくい・・・

例えば、2, 3行だけスクロールさせたいときに、普通ならマウスホイールをちょこっと転がせばいいだけなのに、MacBook Airだと全然思うようにならない。
ちょこっと転がすのだと反応せず、かといって、勢いよく転がすとかなりスクロールされてしまったり。
思ったように反応してくれないのは、かなりのストレス。

これは、Macの場合、スクロールの加速度を加味しているのが原因っぽい。
なので、スクロールの加速度を無視するように設定する必要がある。

対応策

これらの問題に対して、何か1つのツールで対処できればよかったのだけど、残念ながら見つけられなかった。
なので、それぞれの問題に対して、別のツールを用いて対処した。

  • Scroll Reverser
  • DiscreteScroll

Scroll Reverser

まず、「スクロールが普通と逆」問題の解決に使ったのが、Scroll Reverser

このツールは、名前の通り、スクロールの方向を逆にするもの。

上記ページからダウンロードしてきたzipファイルを解凍し、"Scroll Reverser.app"を「アプリケーション」フォルダにコピーすれば、インストールは完了。

ただし、起動しようとすると、おそらくセキュリティに阻まれて起動できないはず。
その場合、「システム環境設定」-「セキュリティとプライバシー」-「プライバシー」-「アクセシビリティ」で、"Scroll Reverser.app"のチェックを入れる必要がある。
(「システム環境設定」-「セキュリティとプライバシー」-「一般」で、実行許可を与える必要もあるかも)

起動したら、メニューバーにアイコン( \Updownarrowみたいなやつ)が表示されるので、アイコンから設定を開き、以下のように設定:

f:id:yamaimo0625:20190715155321p:plain

これで望む挙動にすることができる。

さらに、上記設定の「アプリ」で「ログイン時に開始」にチェックを入れておけば、ログイン時に勝手に開始されるので便利。

DiscreteScroll

そして、「スクロールがキビキビ反応しない」問題の解決に使ったのが、DiscreteScroll

このツールは、スクロールの加速度を無視するようにするもの。

上記GitHubの"releases"にリリースのzipが置かれているので、DiscreteScroll.zipをダウンロード。
そして、解凍して"DiscreteScroll.app"を「アプリケーション」フォルダにコピーすれば、インストールは完了。

こちらのツールもScroll Reverserと同様にセキュリティに阻まれるはずなので、まったく同じように、「システム環境設定」-「セキュリティとプライバシー」-「プライバシー」-「アクセシビリティ」で、"DiscreteScroll.app"にチェックを入れてやる。

あとは、起動させれば、スクロールがキビキビ反応してくれるようになる。

ちなみに、このツールはホントに必要最低限の機能しかないので、起動しているかどうかの確認は「アクティビティモニタ」から行うしかない。
また、終了させる場合も、「アクティビティモニタ」からプロセスを終了させる必要がある。

それと、ログイン時に勝手に起動して欲しい場合には、「システム環境設定」-「ユーザとグループ」で、「ログイン項目」に"DiscreteScroll.app"を追加しておけばいい。


以上のツールを使うことで、かなり快適にマウスを使えるようになった。
MacBook Air使いは、ぜひお試しあれ。

今日はここまで!

「Lucid, the Dataflow Programming Language」を翻訳してみた。(その13)

ちょっと間が空いてしまったけど、前回の続き。

2.8 無限プログラミング

Iswimファミリについてのこれまでの議論は、従来のオブジェクトが有限な代数に限定したものだった。
この形式のIswimは、ALGOLのような従来の命令型言語の再帰的サブセットに多かれ少なかれ一致している。
この制限により、Iswimプログラミングは本質的に、従来のプログラミングの、とても厳密に制限され構造化された形式となっている。

しかし、言語の代数をこのような「従来の」ものに限定する特別な理由はない。
オブジェクトが有限でない代数によるIswimファミリには、興味深く有用なものがたくさんある。
これらの言語は、従来の言語の単なるサブセットよりもはるかに豊かで、まったく新しいプログラミング手法を可能にする。

Iswimファミリで興味深いメンバの一例は、POP-2代数 Pのような代数 Hに基づいたもので、その宇宙(universe)には有限リストに加えて無限リストが含まれている。
リストは無限であってもよく、そのリストの要素は Hの世界の任意の要素であっていい(リストでもいい)。
このアイディアは、以下の「ドメイン方程式」によっていくらか正確にすることが出来て、POP-2の非リストなデータオブジェクトのドメイン Dとして、 Hの宇宙 H_0を定義する:

 L = 1 + H_0 \times L \quad \mathrm{and} \quad H_0 = D + L

最初の式は、「ハイパーリスト」(ドメイン Lの要素)が、空であるか(空リストはただ1つだけある)、 H_0の1つの要素(ヘッド(head))と1つのハイパーリスト(テイル(tail))で構成されていることを示している。
次の式は、 H_0の要素が Dの要素(文字列、数値、単語など)またはハイパーリストのいずれかであることを示している。
これらの式は、 Hでの演算は指定していなく、 Hの宇宙 H_0のみを指定しているので、 H自体は指定されていない。
しかし、これらの式の解が得られれば、通常のリスト演算(hdtl::などの記号で表される)は簡単に定義できる。

実際、これらのドメイン方程式は、無限の長さのリストがあるという解を持つ。
1つ注意しなければならない点は、ドメイン H_0にも豊富な種類の部分的(partial)オブジェクトが含まれていることである。
ドメイン Dでは、部分的(非標準)オブジェクトは \perpだけであり、他のすべてのオブジェクトは、正常で、健全な文字列、単語、整数などであった。
しかし、 H_0では、「混合」リストーーつまり、要素の一部(必ずしもすべてではない)が \perpであるようなリストーーを許可する必要がある。
また、ある時点で「テイルオフ(tail off、尻尾切り?)」する必要があるーーこれは、tlが何度も適用される場合に、ある時点で \perpと評価することである。
最後に、リストの構成要素は他のリストでもよいので、構成要素として部分的リストを持つようなリストを許可する必要がある。
このリストの要素は部分的リストであってもいいし、そうでなくてもいい。
要するに、ドメイン H_0は、すべてのオブジェクトの「純白さ」と \perpの「漆黒さ」との間に無限の多様な濃淡を許している。

(※正直、何を言っているのか分からないのだけど、操作的に考えたときに「無限の操作」を意味する \perpに対して、無限の長さを持つリストも操作が(場合によって)無限になる、ということを言いたいのだと思われる)

Iswim( H)でプログラミングすることと、「有限」オブジェクトの代数 AによるIswim( A)でプログラミングすることの大きな違いの1つは、(前者の場合)変数を再帰的(循環的)に定義するのに意味があるということである。
もう1つの違いは、終了条件なしで再帰関数定義を与えることも意味があるということである。
その場合、「結果」が無限であるので、評価は「永遠に」実行されることになる。

例えば、以下の定義を考えてみる:

 X = 1 \mathrm{::} X;

Iswim( P)では、この定義は \perp Xと関連づける。
というのも、 Pは有限リストのみを持ち、この定義を満たすような有限リストは存在しないからである。
しかし、Iswim( H)には無限を使った解が存在する。
すなわち、

[1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 ...]

という無限に1が続くリストである。
さらに、これはこの方程式の最小解であり、したがって変数 Xに関連付けられた値となる。
次の「非終端」の定義

 \mathit{bump}(X) = \left( \mathit{hd}(X) + 1 \right) \mathrm{::} \mathit{bump}(\mathit{tl}(X));

は、完全に理に適った関数を定義している。
無限の数のリストを引数として期待し、引数の各要素を1ずつ増やすことによって形成される無限のリストを結果として返す。

演算子の結合の優先度が分かりづらい(+ > ::)ので、括弧を追加している。

これを使って、

 \mathit{nats} = 0 \mathrm{::} \mathit{bump}(\mathit{nats});

と定義すれば、 \mathit{nat}はすべての自然数(※ここでは0も自然数に入れている)の無限リスト

[0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 ...]

を定義する。
このリストは、この方程式の最小の(そして、実際のところ、唯一の)解となっている。

無限オブジェクトを持つ代数は、非常に異なったスタイルのIswimプログラミングを可能にし、とてもエレガントな(ただし従来とはかなり異なるかもしれない)プログラムを作れるようにする。
すべての素数の無限リスト

[2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 51 53 ...]

を出力(値)とするようなIswim( H)プログラムは、以下のようになる:

P
where
    nats = 1 :: bump(nats)
    where
        bump(X) = hd(X) + 1 :: bump(tl(X));
    end
    P = 2 :: primesin(tl(tl(nats)))
    where
        primesin(L) = if isprime(hd(L))
                      then hd(L)::primesin(tl(L))
                      else primesin(tl(L)) fi;
        isprime(n) = nodivsin(P)
        where
            nodivsin(Q) = (q * q > n) or ((n mod q ne 0) and nodivsin(tl(Q)))
            where
                q = hd(Q);
            end
        end
    end
end

このプログラムは、自然数の無限リストからすべての非素数を取り除くように動作する。
素数性の確認では、構築中のすべての素数の無限リスト Pを使用している。

Iswimファミリの「無限を扱える」メンバのインタプリタがすでに数多く存在している。
最もよく知られている(そして最初に現れた)のは、Turner(1979)のSASLとHenderson(1980)のLispkitである。
これらの言語は、元の高階言語に基づいていて、IswimではなくISWIMのバリエーションとなっている。
著者の1人(William W. Wadge)は、Warwick大学の同僚と一緒に、先に説明した代数 Hに基づいて、このような「ラムダ微積分」言語を実装した。
(本質的にIswim( H)である)この言語は、PIFL(POP-2 Influenced Functional Language)と呼ばれ、学部の関数型プログラミングの授業で使用されている。

PIFLはpLucidの「仲間の」言語で、同じ代数に基づいていて、同じ構文規則を使用している。
その結果、この2つの言語には大きな重なりがある(PIFLでもwhere再帰的となっている)。
多くのPIFLプログラムは(構文的に)pLucidプログラムでもあり、同じ出力を生成する。
pLucidとPIFLとの交わりが、(大雑把に言えば)一階のPIFL、すなわちIswim( P)となっている。
(PIFLではリストの再帰的定義が必ず \perpを返すわけではないので、ぴったりIswim( P)というわけではない)
Iswim( P)ーー言い換えれば一階で有限なPIFLーーのことを、「pIswim」と呼ぶことにする。
Iswim( H)(一階で無限なPIFL)のことは、「HyperpIswim」と呼ぶことにする。
したがって、pIswimはpLucidの部分言語であり、HyperpIswimはPIFLの部分言語である。
この節の例は、すべてのHyperpIswimのプログラムであり、(したがって)PIFLのプログラムでもある。

無限オブジェクトでの計算を可能にするIswimファミリのメンバは、より洗練された実装を必要とすることは明らかである。
Iswim( H)のような言語に直面したとき、Iswim( P)のような言語を(かろうじて)カバーしていた従来の逐次的な解釈は、完全に破綻することになる。
特に、変数の再帰的な定義は、完全に理に適っていて有用であるものの、代入文と見做しては意味をなさなくなる。

しかし、他の2つの実装方法(すなわち、簡約(reduction)と要求駆動(demand driven))は、拡張できる。
簡約による方法は最も簡単に拡張できる。
以下のような、無限のデータに対する演算を含む式をどうやって書き換えるかという式を使うだけである。

 \mathit{hd}(X \mathrm{::} Y ) = X;

PIFLインタプリタは、SASLやLispkitの実装と同様に、この方法で動作する。

要求駆動も拡張できるが、ここではさらに注意を要する。
ある式の値が無限の場合、その式の値を要求することは出来ない。
なので、代わりにその値の一部、すなわち、他の部分的な要求を満たすのに必要な分だけを要求しなければならない。
計算の過程で、同じ値のより多くの部分が要求されるかもしれないが、一度にすべての値を必要とすることはない(これはpLucidインタープリタの仕組みとなっている)。
しかし、オブジェクトの「一部」を構成する概念は問題のオブジェクトの性質に依存するため、一般的な要求駆動インタープリタではない。


ということで、無限リストに関する話。

Haskellで(遅延評価によって)無限リストを扱えるのと同様に、Iswimでも無限リストを含むような代数を考えることで、無限リストを使ったプログラミングが可能になる、と。
これを実際に実装した言語がPIFLという言語で、pLucidとは兄弟のような関係になっているっぽい。

というのも、pLucidだとリスト自体は有限のものしか扱えないはずなので、PIFLはpLucidの部分言語というわけではないから。
けど、じゃあpLucidは無限を扱えないのかというと、そんなことはなくて、pLucidではPIFLと違って変数自体が時間方向に関して無限リストのように伸びていっている。

対比で書くと、時間という概念は持ち込まずに無限リストというオブジェクトを作り上げたPIFLと、時間という概念を持ち込んで時間方向に無限リストにしたpLucidという感じ。
どちらも無限を扱えるように拡張されているのだけど、その伸びていく方向が違う。
なので、兄弟のような関係と言える。


何はともあれ、2章はこれで終わりで、長かったIswimの話もここまで。
3章は、このIswimに時間方向の値のリストを持つ代数を入れたLuswimという言語を見ていくことになるっぽい。

今日はここまで!

『正義の教室』を読んでみた。

飲茶さんの新刊、『正義の教室』を読んでみたので、その感想とか。

正義の教室 善く生きるための哲学入門

正義の教室 善く生きるための哲学入門

「正義」って何だろう?

この本でまず驚いたのが、小説だということ

哲学の入門書なので、飲茶さんがこれまで出してきたような解説本を想像していたのだけど、いざ読み始めてみたら、なんと小説。
しかも、本題に入るための小噺だけ物語になってるとかではなくて、哲学の説明まで含めて、すべて登場人物たちによって語られ、描かれている。
これにはホント驚かされた。
しかも、物語が普通に面白いw

飲茶さん、多才だなぁ・・・

そんな、小説を通して語られ、説明されているテーマが、「正義」。
「正義」って何なんだろうね、ということ。

これに関して、本書では「正義には3つの判断基準がある」としている。
すなわち、

という3つの立場を挙げ、それぞれについて説明し、また、問題点の指摘も行っている。

これらの説明はさすが飲茶さんで、とても分かりやすい。
それに、それぞれの立場を体現したヒロインたちを登場させてストーリーを展開しているので、面白く読み進められるし、共感もしやすい。
ぜひとも実際に本を手にとって読んでもらいたいところ。

・・・が、ぶっちゃけ、そんなのどうでもいいんだよ!

というのが、この本を最高にファンキーにして、めちゃくちゃ面白くしている部分w

そう、哲学書に教養を求める人ならば、功利主義だとか自由主義だとか、そういった知識を得ることが重要になるんだろうけど、じゃあ、そういった知識を得たからといって、何になるんだ、と。

「トロッコ問題」のような理不尽な状況に実際に置かれてしまったとしたら、そういった知識がなんか役に立つのか?
クソの役にも立たないだろ!!!

実際、飲茶さんは本書を書いた動機として、以下のようなツイートをしている:

めっちゃ分かるw
理不尽でしかないもんね。
物語内では、この理不尽さにヒロインの一人が苦しめられたり。

そして、本書で説明されている3つの立場も、それぞれ問題点が指摘され、ことごとく論破されている。

じゃあ、「正義」なんてものはないのか・・・?

いや、「正義」はあるよ!!!

そう強く主張しているのが、本書。

ロッコ問題という状況で、どんな「行動」が正義と思えるかではなく、どんな「人間」が正義だと思えるか。
(中略)
人間は、完全な正義を直観できないし、知りようもない。
それはどうしようもない現実だ。
でも、そんな何が正しいかもわからない世界の中でも、それでも「正しくありたい」と願い、自分の正しさに不安を覚えながらも「善いこと」を目指して生きていくことはできる。
きっと僕たちにはそれで十分でーーむしろ、それこそが人間にとって唯一可能な正義なんじゃないだろうか。
(『正義の教室』より引用)

つまり、大切なのは「内容」ではなく、「在り方」だということ。

結局のところ、功利主義自由主義直観主義も、「これが正義である」という「内容」に関する立場の違いでしかない。
なので、そんなのは「どうでもいい」となる。
そうではなく、「自分はどうやって生きていくのか」という「在り方」こそが重要というわけだ。

そんな主人公の最後の演説シーンで語られる内容は、まさにニーチェの「超人」を体現するようなものになっていて、とてもよかった。

そして、衝撃のラストw

いやまぁ、途中で予想はついたんだけど、まさかホントにこれをやるとはw
『史上最強の哲学入門』の東洋編で、頭で分かってるだけじゃダメで、リアルな体験をもって理解しないといけない、と書かれている通りなんだけどw

今日はここまで!

正義の教室 善く生きるための哲学入門

正義の教室 善く生きるための哲学入門

技術書典7 はじめてのサークル参加meetupに行ってきた。

f:id:yamaimo0625:20190621155528j:plain

はい、というわけで、技術書典7にサークル参加で申し込んだ。
当選したら、技術書生やす!

技術書典については、以下の公式ページや、自分が一般参加したときのレポートを参照:

はじめてのサークル参加meetup

今回行ってきたのは、以下のイベント:

技術書典にサークル参加しようと決めたはいいものの、分からないことがいろいろあったからね。
特に、今回はオフセット本にチャレンジしてみようと思っているのだけど、オフセット本は作ったことがないので、そのあたりの疑問を解決できればな、と。

ちなみに、このブログでも何度か紹介してるけど、同人誌自体は一応作ったことがある。
技術書でもないし、コピー本を凄くしたようなものなので、普通の人が想像する「同人誌」と呼んでいいのか迷って、「どきどき初参加」枠で申し込んだけど・・・

自分が作った同人誌に関しては、以下の記事から:

PDF版をBOOTHでも販売しているので、興味があれば、ぜひ。

イベントは、わかめさんひつじさんがスピーカーとなって、質疑応答を交えつつ、そも同人誌ってなんじゃらほい、というところから、その製作方法やスケジュール感、執筆での注意点や当日の様子などについての話があった。
以下は、その中で特に自分が参考になったことのまとめ。

スケジュール感

まずはスケジュール感から。

同人誌を作る場合、原稿を書いて、ハイおしまい、というわけにはいかない。
特に、印刷所を使ってオフセット本を作るとなると、その入稿の締め切りも考えないといけない。

大まかな流れは、以下の3つのステージになる:

  1. 執筆前:計画、企画
  2. 執筆 :執筆、編集
  3. 執筆後:印刷、広報、頒布

まず、計画、企画では、各工程の期日を決めて線を引いたり、書く本の内容を決めていく。

次に、執筆ではもくもくと原稿を書く。
執筆はだいたい1ヶ月を目安とするみたい。
また、レビューや校正も必要。
それと、本としてまとめるために、表紙を作ったりレイアウト・スタイルを整えたりといった編集も行なっていくことになる。

最後に、印刷所に入稿して、広報活動と、当日の頒布。
告知は積極的にやった方がいいとのこと。

上記を踏まえると、以下のような感じになる:

時期 やること
7月上旬 当落結果発表、参加費支払い、計画・企画
7月〜8月 この中で1ヶ月くらいとって執筆し、編集、レビュー、校正
9月上旬 入稿、広報活動
9月22日 イベント当日!

以下の手順でカレンダーを取り込むことも出来るみたい:

執筆環境

さて、いざ執筆しようと思ったら、執筆環境が必要なわけだけど、そこで挙がるのがRe:VIEWとかMarkdownとか。
(あるいは、 \TeXで頑張るとか)

普段、Markdownで文章を書くのに慣れているので、正直、書式が違うRe:VIEWを使うのは微妙かなぁ、とも思っていたんだけど、いくつか追加で考慮すべき点があった。

まず、Markdownだと脚注を書くのが難しいよ、という話。
実際のところ、はてなブログだと拡張が入ってて、脚注も書けるようになっているのだけど(Markdownで書いてみた。(まとめ) - いものやま。も参照)、その拡張が使えるとは限らない。
それに、この拡張の例からも分かるとおり、Markdownには方言もけっこう多いので、そのあたりも悩みのタネになる可能性も。
その点、Re:VIEWだと脚注も問題なく使える。
また、マークアップ言語なので拡張もしやすいとのこと。

あと、Re:VIEWは実際に同人誌製作に使われた実績も多いので、印刷まわりで安心できる、というのも大きい感じがする。
例えば、印刷所によっては全ページにノンブルを入れる必要があるけど、Re:VIEWだとその辺もうまくやってくれるとのこと。

う〜ん、悩ましい。
今回は \TeXの勉強も兼ねて \TeXでやろうと考えていたのだけど・・・
Re:VIEWを使う方が無難な気もする(^^;

執筆のアドバイス

執筆に関してもいくつかアドバイスがあった。

まず、書きたい内容に絞って書いた方がいいよ、という話。
説明を書いてると、どうしても「あれも説明しなきゃ」「これも書いておかないと理解してもらえないかも・・・」となっていきがち。
けど、それで書きたい内容が書けなかったら、本末転倒。
本題に入る前に力尽きたり、あるいは最悪、原稿を落としたりしたら、悲しすぎる・・・
なので、まずは書きたいところから書いていき、レビューをしてもらって「ここらへん、説明が足りないからよく分からない」と指摘されてから説明を継ぎ足すくらいでもいいんじゃないか、とのこと。

あと、書いてるときはバックスペース禁止というルールでやるのもいいっぽい。
バックスペースを許すと、書きつつ推敲を始めてしまって、いつまでたっても文章が完成しないことがあるから。
これ、めっちゃ分かる・・・
(書いてるときにどうしても推敲してしまうので、めちゃくちゃ遅筆・・・)

それと、校正に関しては、余裕がない状態でtypoを見つけたりなんか出来ないので、余裕を持ってやるようにねとのこと。
確かに・・・
あと、実際に紙に印刷した方が間違えを見つけやすい人も多いので、実際に印刷してみるといいかも、とのこと。
実際、自分も『哲学散歩道』の校正をやるときは紙に印刷してやったので、その通りだと思う。

他には、爆死しないためには、表紙の分かりやすさが大切、という話もあった。
たくさんの本があるので、まず表紙で目がつくかどうかが重要になる。
そして、その本が自分を対象としたものでない(not for me)と思われてしまったら、手にとってもらえさえしない。
なので、表紙で何について書かれた本なのかや、扱っている内容、あるいはレベル感が分かるようになっていた方がいいとのこと。

サイズや部数をどうするか

実際に同人誌を作るときに悩ましいのが、本のサイズをどうするか。
A5にするのか、B5にするのか・・・

ちなみに、A5でもB5でも、1ページに入る文字数はそれほど変わらないらしい。
これは、A5の場合は文字サイズも少し小さくすることが多いから。

一般に多いサイズはB5。
コードを載せる場合には、B5の方がプログラムのリストが見やすいという利点があるっぽい。

一方、A5だと、気軽な読み物という雰囲気を出しやすい感じがあるっぽい。
B5に比べて小さいので、軽いし。
あと、個人的には表紙のデザインがやりやすそうな気はしてる。
(面が大きい方がイラストや写真も大きいものが必要になるし、ダサいスキマを作らないデザインにするのはなかなか難しい)

あと、何部刷るのかというのもなかなか悩ましい問題。

データによれば、技術書典だと新刊が平均150部くらい出る感じらしい。
機会損失をしたくなければ、それより多めに刷っていた方がいいし、完売するというのはかなり楽しいので、少なめに刷るというのもありみたい。
なお、少なめに刷った場合、電書版のQRコードを名刺などに印刷して用意しておけば、機会損失もだいぶ抑えられるので、そういうのもあり。

ただし、注意点として、技術書典は部数に関して例外的で、他のイベントで同じような部数は刷らないように、とのこと。
在庫を大量に抱えて、悲しいことになるっぽい・・・

部数に関しては、個人的に気になっていたことも聞いてみた。
それは、同人誌の束はどれくらいのサイズ(分厚さ)になるのか、ということ。
運搬するときや、在庫が残ってしまったときには、そのサイズが重要になってくるので。

これは、同人誌100冊で、500枚入りコピー用紙の束が5つ入ったダンボールくらい、という回答をもらって、すごくイメージしやすかった。

実際、50ページの同人誌を考えてみると、1冊あたりの紙は25枚で、それが100冊となると2500枚となり、これはコピー用紙500枚x5束の2500枚と計算があう。

製本サービス

他、面白い情報として、製本サービスの話があった。

セブンイレブンのマルチコピー機はかなり優秀らしいので、コピー本を作ったり、試し刷りをしたりするのに使えるっぽい。

あと、製本直送.comというサービスもあるとのこと。

電書版のみ頒布するという場合も、見本誌があった方がいいので、そういう場合にはこういった製本サービスを使用して見本誌を用意するといいみたい。

なお、紙の本を出版する場合も、「これが見本誌」と分かるようにして見本誌を用意しておいた方が、手にとってもらいやすいみたい。
具体的には、ビニールのカバーなどをかけて「見本」とタグを貼っておくとか。
言われてみればなるほどという感じ。

印刷所とのやりとり

今回、初めてオフセット本を作ろうと思っているので、そこで気になっていたのが、問題なく印刷してもらえるのかどうかということ。
いざ印刷されたものが届いてみたら、思わぬ乱丁があったりレイアウトが崩れたりなんかしていたら、目も当てられない・・・

これに関しては、入稿後に2, 3回くらい印刷所とやりとりすることになるっぽい。
これだと印刷に問題が出そうだけど、大丈夫か、とか。
そういうのがあるなら、安心かな・・・?
もちろん、指摘に対応するだけの余裕を持って入稿する必要があるわけだけど。

ちなみに、依頼しておけば見本誌を送ってもらうとかも可能っぽい。
ただし、これは印刷されたものが送られてくるだけで、それを見て原稿を手直ししたり出来るわけではないようなので、注意。
もし、ちゃんと印刷されるかなどを確認したいなら、前述の製本サービスを使って試し刷りをして、入稿に備える感じになるみたい。

あと、わかめさんが以下のツイートをしていたので、それも参考になりそう:

かんたん後払い

あとは、技術書典特有のものといえば、「かんたん後払い」。

これは、コードを専用アプリで読み取ることで購入手続きを完了させ、あとで支払いを行えるようにする、というサービスなのだけど、サークル参加するとなると、サークル側で何か特別な準備は必要なのかどうかが気になっていた。
例えば、何か特別な機械を用意したりだとか。

結論から言えば、そういった特別な機械とかは必要なくて、規約を読んで申し込みをすればいいだけみたい。
そうすると、当日にコードが印刷された紙が渡されるので、あとはそれを専用アプリで読んでもらえばいいだけっぽい。

ただ、注意点として、現金ほどスループットは出ないという話があった。
なので、お釣りの用意はしっかりとね、とのこと。


ちなみに、作ろうとしている技術書は、以前このブログで書いたポーカーの記事を膨らませたものにしようと思っている。
技術者なら、やっぱりゲームもガチで数理モデルを使って勝ちに行きたいでしょ?w

上の記事で導き出したインプライド・ポットオッズの話は、とても興味深い(そして強化学習のモデルのいい例にもなってる)ものなので、多くの人に知ってもらいたいし、他にもいくつか調べて文章にしたいネタがあるので。

もちろん、ポーカー(テキサスホールデム)やったことないという人も多いと思うので、そこらへんも出来ればカバーする感じで。
(ただ、それで書きたいことが書けなくなったら本末転倒なので、省略するかも)

ポーカーを覚え、数理モデルを駆使して、狙え一攫千金!ってねw

今日はここまで!

「Lucid, the Dataflow Programming Language」を翻訳してみた。(その12)

前回の続き。

2.7 遅延評価

しかし、Iswimの操作的(動的)解釈として、より適切なものがある。
この方法論では、プログラムは実行されると考えるのではなく、プログラムは評価されると考え、その評価は必要に応じて行われるとする。
この評価の方法は、必要以上には評価を行わない(=必要になったときに必要なだけ評価を行う)ので、「遅延」と呼ばれる。
特に、関数呼び出しの実引数は自動的には評価されない。
この遅延評価の方法は、数学的意味論により忠実となっている。
実際、ちょっとした注意を払うことで、それらは完全に正しいものになり、形式的意味論が指定するものを正確に生成する。

これらのうちの最初のものは、「要求駆動(demand-driven)」解釈と呼ばれるかもしれない。
この方法では、プログラムの一部(最初はプログラム全体)の値に対する要求が、部分式の値に対する要求を生成する。
要求は感染症のようにプログラム全体に伝播していき、必要とされた値が要求元へと流れ返っていく。
2つの部分式 E_1 E_2の合計 E_1 + E_2を評価するために、評価マシンは E_1 E_2を(おそらく並行して)評価し、それらの結果を加算する。
個々の定数からなる式を評価するために、評価機は代数によって定数に割り当てられた値を返す。
個々の変数からなる式を評価するために、評価機は変数の適切な定義を検索し、その定義の右辺を評価する。
対象の変数が関数定義の仮引数である場合、対応する実引数を探し出してきて、それを評価する。
評価する式が if  C then  E_1 else  E_2 fiという形式であれば、まず Cを評価して、その真偽値にしたがって、 E_1 E_2のいずれかを評価する。
最後に、(例えば) f(E_1, E_2)という形式の式を評価するなら、 fの定義を見つけ出し、その右辺を評価する。

もちろん、要求駆動型の評価は、上記のざっくりした説明が示すよりも、もう少し複雑である。
それにもかかわらず、実装することはそれほど困難というわけではなく、完全に正しい。
(付録のマニュアルに記述されているpLucidインタプリタは、要求駆動の評価スキームを使用している;そして、Iswim( P)はpLucidの部分言語である)
(※データフロー言語の実装を考えるとき、pull型(シンク側から要求を出し、それに応じてソース側が計算を行う)とpush型(ソース側で計算を行い、結果をシンク側に流してシンク側を駆動させる)を考えることができるけど、この要求主導というのはpull型だという主張。実際の実装がそうなっているのかは未確認・・・)
要求駆動型のモデルは、プログラミングを助けるうえで、適切なものとなっている。
要求駆動型の観点では、定義が実行可能な順序で現れてくる必要はない。
実際、この方法だとプログラムを書くときによりトップダウンな形で書くことが出来る。
まず、欲しい出力の値となる式を書く(そこで使われる変数や関数の定義は書かない)。
この式はwhere節の主題になる。
次に、where節の本体に、必要に応じて主題で使われる変数の定義を書いていく。
したがって、要求駆動のインタプリタは、書かれたのと同じ順序で定義を進めていく(これはインタプリタにとって特別な助けになるというわけではない)。
この「必要に応じて定義する」アプローチは、プログラミングのスタイルをずっと良くし、Iswimの定義型の精神により合っている。

Iswimプログラムを実装する非逐次的な別の方法もある。
そのアイディアは、第7章で議論されるプログラム操作の規則を使用するもので、ソースプログラムを徐々に出力に変換していくものである。
変換方法は、プログラムの定義を書き換え規則として使用する。
実行する簡約(reduction)を選択する戦略が慎重に定義されている場合、実装は必要とされない式の値を評価しようとはしない。

この方法(簡約計算)は非常にシンプルであるが、プログラミングの助けとして無制限に推薦することは出来ない。
中間表現は非常に大きく、複雑になり、元のプログラムとの関係がほとんどなくなる。
この方法は主に構文的であり(※ここでの「構文的」というのは、記号操作的、という意味合いだと思う)、構文に関して排他的に考えるプログラマは、Iswimの意味論を理解するという利点を失う。
プログラマは、関数定義を「関数」ーーすなわち、データを変換する「デバイス」ーーの定義と考えるべきである。
定義をテキストを変換する書き換えルールと考えることはお勧めしない。
記号操作というより、計算であると考えたほうがいい。
(※ラムダ計算の理論では、定義による置換を行うことで計算が出来るとしていて、その置換の戦略によって遅延評価かそうでないかが変わってくる。ここで述べているのはその簡約による方法)

これらの代替操作的モデルは、どちらも \perpの意味をそれぞれの方法で大事にしている。 例えば、次のような定義を考えてみる:

X = X + 1;

要求駆動のインタプリタは、 Xの値に対する要求が Xに対する別の要求に直接つながるため、(要求が)無限に循環することになる。
そして簡約の実装は、 X X + 1に無限に置き換えることで、以下の系列を生み出すことになる:

 X +1, (X +1)+1, ((X +1)+1)+1, \cdots

どちらの場合も、計算は決して終わることなく、これはまさに \perpに対応する操作的な活動になっている。

最後に、プログラマは動的モデルをまったく使用しないことを望むかもしれないということを指摘しておく。
Iswimの最大の強みは、公式での意味論が厳密に静的であり、よく理解されている関数の概念を使用していることである。
プログラマがプログラムの効率(性能)を心配していない場合、実際の操作的な概念を考える必要はまったくない。
プログラマがもっぱら正しさにだけ関心を持つ場合、静的な意味論はプログラムの出力を完全に指定するので、静的な意味論だけで十分である。

しかし、一般的に、プログラマは性能に関する質問を無視できない(そうでなければ、プログラムはなく、仕様のみがあることになる)。
プログラマは、いくつかの操作上の観点から思考し、それを実行するのに必要なリソースの量を減らすようにプログラムを作らなければならない。
しかしこれは、プログラマは実装のあらゆる細かい部分について心配する必要があるだとか、実装のあらゆる部分の動作について理解している必要があるだとか、そういうことではない。
とても実用的なプログラミングでさえ、純粋に宣言的に理解されている部分があるだろう。
さらに、最も実用的で効率的なプログラムでさえ、その正しさは、表示的な(静的な)意味にのみ依存し、操作的なアイディアを参照することなく考えることが出来る。
「抽象性」という用語は、本質的に表現または実装の問題から独立であることを意味する。
したがって、Iswimの形式的で表示的な意味論は抽象的な意味論であり、この言語を使用したいと思う人であれば誰でも理解できるものである。


ということで、遅延評価に関して。

この節に書かれてることはとても興味深くて、遅延評価といえばHaskellが有名なわけだけど、Haskellが遅延評価を実現している方法はまさにこの節で書かれている2番目の方法(簡約による方法)で、簡約の戦略を非正格にすることで評価が遅延するようにしている。
一方で、pLucidはそれとは別の方法で遅延評価を実現していると言っていて、それが1番目に書かれた要求駆動による方法。
データフローの視点で考えることで、1番目の方法が出てくるのはとても面白い。

また、データフロープログラミングの後継と言われることの多いリアクティブプログラミングだと、(オブザーバ・パターンによる)push型の実装が多い印象なんだけど、pLucidはそうではなく、pull型の実装になっている、と。
確かに、push型だと遅延評価は無理だけど、pull型なら実装はWorkStealingアルゴリズムみたいに関数呼び出しを一つのタスクとしてスタックにプッシュする感じになりそうなので、遅延評価になりそう。
いやー、なるほどという感じ。

今日はここまで!