今日、コインハイブ事件への意見書を送付した。(郵送はまだ)
草稿をここで公開しておく。 コインハイブ事件への意見書草稿
本質的に、わたしたちは概念をフォローしたいのである。
あなたがツイッターで、その人をフォローする理由はなんだろうか。その人自身が本当に好きなのだろうか。単に、好みの記事や、写真や、動画をRTしてくれるから、ではないだろうか。実際に、おもしろ動画botのようなものがあり、それをフォローする人間はたくさんいる。
人間ではなく、概念をフォローするには、どうすればいいだろうか。たとえば、ハッシュタグを追うこともできる。ハッシュタグは、すなわち直に概念に結びついた記号だ。しかし、今のツイッターは、話題を検索することはできても、ハッシュタグを直接フォローすることはできない。
ハッシュタグは、書き手が恣意的に設定しなければならないという点で、ウェブページに設定されたキーワードと同じような、簡易な仕組みだ。それは、機械が直接文章から概念を抽出することができない、あるいは抽出するコストが高いということが前提にある。しかし、わたしたちは現に文章から概念を抽出している。それは、全文検索 Full Text Search という技術がやっていることだ。
全文検索システムは、その名からは想像が付きづらいが、直接文字列を検索するのではない。そうではなく、文章を「語」ごとに分割し、語によってデータの転置操作を行い、索引を作成する。そうすることで、語が与えられると、効率的に、語に結びついた文章を引いてくることができる。そして、語はやはり概念に結びついた記号である。つまり、全文検索を実現する段階で、わたしたちは文章から概念を抽出しているのである。
わたしたちは文章からある程度の精度で概念を抽出する技術を持っているのだが、本来は概念をフォローすることができてもおかしくないのだが、そうはなっていない。わたしたちは概念をフォローするのではなく、ボットをフォローしている。しかし、検索システムは任意のフレーズで自由に検索できるのに対し、ボットは限られた概念しかRTをしてくれない。これは非常に不自由なことだ。人間は有限だが、概念は無限だという問題がある。
わたしたちは、分散SNS上で、概念のフォローを実装できるかもしれない。ActivityPubで、人間のかわりに、概念をフォローできる仕組みが作れるはずだ。インスタンスは、各個人のoutboxの公開アクティビティーから概念を抽出し、概念のoutboxに入れる。この概念のoutboxを、フォローできるようにすればよい。また、概念のoutboxそれ自体が転置インデックスの役割を果たし、インスタンスに対する全文検索機能を提供する。概念のoutboxは仮想的に無限に存在するが、その無限のoutboxを一括でフォローする仕組みがあれば、作成された転置インデックスを他のインスタンスに転送することもできる。もちろん、興味がある概念だけをフォローしてもよい。
個人は特定のインスタンスにしか存在しないが、概念はあらゆるインスタンスに存在する。そこで、上の考えの発展として、概念のフォローは、インスタンスを特定しない形式によるフォローができることが望まれる。インスタンスを特定せず、すべてのインスタンスの特定の概念をフォローできるようにする、あるいは、概念のフォローに関する情報を、連合インスタンス全体に伝播させる仕組みがあれば、わたしたちは、透過的に、純粋な概念をフォローすることができる。
人間やボットを介せず、純粋な概念によって構成されたタイムラインを、わたしは見てみたい。
GitHubのExplore repositoriesにたまたま表示されていた TopShell が気になったので、ここで紹介する。
TopShell開発の動機は TopShell: Reimagined Terminal and Shell · topshell-language/topshell Wiki · GitHub に書いてあるが、要点をまとめると「古典的なUnixシェルを使うのはつらい。いいところだけを抜き出して、全くシェルを考えたら、どうなるだろうか?」ということらしい。
set -u
を使えばエラーになる。】set -e
とか set -opipefail
を使えばエラー時に中断される。】sed
や awk
の不思議なコードを覚えないといけない理屈はともかく、TopShellはブラウザから使うことができる。次のリンクからプレイグラウンドを開いて、試してみよう。
http://show.ahnfelt.net/topshell/
https://github.com/topshell-language/topshell#http-example のサンプルコードを画面左側のエディタに入力すると、直ちに評価結果が右側に表示される。といっても、副作用が発生するタスクやストリーム(バインド文 x <- e
で宣言されているもの)は、行にカーソルをあわせて Ctrl + Enter で1文ずつ実行するか、実行ボタンを押すまでは実行されない。感覚的には、シェルというより Jupyter Notebook に近い気もする。
json <- Http.fetchJson {url: "https://reqres.in/api/users?page=2"} people : List {id: Int, "first_name": String, "last_name": String, avatar: String} = Json.toAny json.data htmlImage = url -> Html.tag "img" [Html.attributes ["src" ~> url]] peopleWithImages = people |> List.map ( p -> {image: htmlImage p.avatar, name: p."first_name" + " " + p."last_name"} ) peopleWithImages |> View.table
ストリームのサンプルとして https://github.com/topshell-language/topshell#stream-example も試してみよう。この例では、時計のアニメーションが動く。
言語仕様についてはまた今度書く。
記号の正逆ピラミッドのうち、少なくとも逆ピラミッドは、OSI参照モデルのレイヤー構成と対応すると考えられる。逆ピラミッドは基底部から頂点へ向けて順にアナログ信号/デジタル信号/プログラムとなっているが、これがOSI参照モデルの第1層 物理層が逆ピラミッドのアナログ信号、第2層 データリンク層~第6層 プレゼンテーションまでがデジタル信号、第7層 アプリケーション層がプログラムと、対応している。
OSI参照モデルの規格書 ISO/IEC 7498-1:1994 は、次のリンクからダウンロードすることができる。
Information technology – Open Systems Interconnection – Basic Reference Model: The basic model
OSI参照モデルにおいて、各システムは物理層によって相互接続されている。この層は物理的な信号を流すことができるが、その信号は、減衰するしノイズも混じる。また、数えきれない機器が接続されているから、どのようにして目的の機器に情報を伝達するかという問題もある。OSI参照モデルはその問題を解決し、遠隔地の任意のプロセスどうしが相互に通信できる仕組みのモデルとなっている。
3階層の記号の(逆)ピラミッドと比べて、OSI参照モデルは7階層もあるのは、OSI参照モデルでは各レイヤーごとに通信を実現する上で求められる機能を、各層ごとに細く定義しているからだが、現実にインターネットで使われている通信技術はOSI参照モデルのように行儀よく積み上がっているわけではなく、複雑に組み合わさっているので、その点はOSI参照モデルに縛られず考えてもよい。
とにかく、機械間の通信階層を考える重要なのは、下層で取り扱うノイズが混じったり欠損したりする信号が、各通信階層の提供するエラー訂正やパケットへの分割・再送、輻輳制御といった機能によって、上層では文字列の理想的の転送として見えるようになることが大事だ。すなわち、プレゼンテーション層のレベルでは、ある機器で入力した文字列表現が、遠隔地の好きな機器に、そのままの形で、あたかもテレポートしたかのように出力される。
このようにして確立した文字列の転送の上に構成されているのがアプリケーション層の諸プロトコルで、SMTPやHTTP/1.1のように、このレイヤーの表現は、テキストを伝送する限りにおいては、人間が読んでも容易に理解できるプロトコルも多い。(マルチメディアが伝送されるようになると、話は変わってくる。)
ひとつ問題として、OSI参照モデルが機械間の通信のモデルであり、人間・機械間の通信を図示していない。人間を図に加えるとするならば、どうなるべきだろうか。人間も機器と同様に、物理層で他のシステムと接続されていることは確かだ。機器どうしは電線や無線で接続されている一方、人間は各種入出力デバイスを介して接続されている。そして人間の認知システムを通して、人間はその記号を認識する。この部分の構造は、機械とそれほど変わるようには思えない。記号の正逆ピラミッドは両ピラミッドを逆向きに置いているが、底を揃えて、並置する形で図示してもよいはずだと思う。(下のツイートで言及した、ISO/IEC 7498-1:1994の図のような感じ。)
ISO/IEC standard 7498-1:1994 に載っている図。OSI参照モデルに言及するときは、この図をちゃんと載せるべきと思うんだけど、省略されている気がする。Wikipediaも載せていない。 pic.twitter.com/Yg9bYt7683
— Ryusei (@mandel59) March 9, 2019
上述したとおり、プレゼンテーション層の文字列表現は人間が読むことができる。(おそらく、そういった理由でプレゼンテーション層と呼ばれているのではないかと思う。)それは、この層の表現は、人間の思う文字列表象を、文字コード表を相互変換表として使うことで、表現できるように作られているからだ。(プレゼンテーションが表現している文字列表現は、抽象文字に対応するものであって、字形に対応するものではない。原則として、ローマン体とイタリック体の差異といった文字の形の差異は、このレイヤーでは捨象されている。)人間の思う文字列の情報が保存されているから、プレゼンテーション層の表現を(文字コード表を介して)人間がそのまま読むことができるし、その文字列の上に人間や機械が処理するアプリケーション層の言語を実装することができる。(もちろん、現在よく使われているUnicode文字列の処理を安易に容易だというのは憚られるが、Unicodeの処理が難しいというのは技術上の問題以前に、世界中の文字の多様性と複雑さが反映されているからという側面もある。)
マルチメディアを伝達する場合はどうか。例えば音声を伝達する場合は、録音装置が、環境の音をディジタル信号に変換する。それは、文字列(厳密にはオクテット列)だが、文字コード表のかわりに、サンプリング定理を介して、連続的な音声信号と結び付けられている。サンプリング定理は、標本化周波数が、元の信号の最大周波数の2倍より大きい場合に、元の信号が復元できるというものだ。実際のところ、アナログ信号をディジタル信号に変換するには、標本化の他に量子化も行うが、いずれにしろ数値に変換できてしまえば、それは通信で送ることができる。人間も、見た画像や聞いた音声を言語化して伝えることは可能だが、機械が行うそれと比べると、画像や音声の再現度は大きく落ちるだろう。(ただ、たとえば証言から似顔絵を描いて犯人を探すというようなことを考えると、犯人を特定するのに十分な情報が含まれていて、それを他人が認識できればいいわけで、機械の符号化した表現が実用上は過剰だったり、ノイズとして有害に作用する場合も考えられる。)
追記:機械の場合は、文字列表現を正確に転送するという目的から設計された層が基盤にあり、その層を活用して、その上に諸プロトコルが実装されることが多い。(絶対的に文字列表現である必要性はなく、データを細かい塊に分割したデータグラムを基礎としたプロトコルなどもある。ただ、文字列上で、人間が読めるように作られたプロトコルは、流れてくる情報を人間が見て意味が理解しやすいという利点がある。)一方で、人間の表象は機械ほど正確に転送することはできない(たとえば伝言ゲームでも徐々に変わってしまう)
オブジェクトの位置の表現方法には、大きく分けて2種類ある。ここではそれを、外延的表現と内包的表現と呼びわけ、ボードゲームの駒の位置の表現を具体例にして、どのような違いがあるかを考えてみる。
今、将棋盤上においてある、王将の位置を表したい。どのような表現が考えられるか。(王将なので、手駒や成りについては考えないこととする。)
ひとつは、将棋盤を2次元配列として用意し、駒の位置に該当する要素として、駒の識別子を代入するものが考えられる。
// コード1 let 将棋盤 = Array.from({ length: 9 }, () => Array.from({ length: 9 }, () => null)) 将棋盤[8][4] = "王将"
コード1を実行した結果、 将棋盤
は次のような配列になる。駒の位置は、将棋盤配列上の特定の要素として駒を表す識別子 "王将"
を格納することで表現している。このような表現方法を、位置の外延的表現と呼ぶことにする。
[ [ null, null, null, null, null, null, null, null, null ], [ null, null, null, null, null, null, null, null, null ], [ null, null, null, null, null, null, null, null, null ], [ null, null, null, null, null, null, null, null, null ], [ null, null, null, null, null, null, null, null, null ], [ null, null, null, null, null, null, null, null, null ], [ null, null, null, null, null, null, null, null, null ], [ null, null, null, null, null, null, null, null, null ], [ null, null, null, null, "王将", null, null, null, null ] ]
これは 将棋盤[8][4] == "王将"
である点で次の表現と大差ないので、簡潔にこちらを使って考えてもよい。
{ "8": { "4": "王将" } }
もうひとつの方法では、将棋盤を連想配列として用意し、駒に該当する要素として、駒の座標を代入する。
// コード2 let 将棋盤 = {} 将棋盤["王将"] = [4, 8]
コード2を実行した結果、 将棋盤
は次のようなオブジェクトになる。駒の位置を座標で表現するこの方法を、位置の内包的表現と呼ぶことにする。
{ "王将": [4, 8] }
位置の外延的表現と内包的表現の違いですぐ分かるのは、配列の添字と要素の関係が入れ替わっていることだ。外延的表現では、座標が添字、識別子が要素となっている。一方、内包的表現では識別子が添字、座標が要素だ。
このことは、情報へのアクセスの容易さと関わってくる。外延的表現では、位置からオブジェクトを得ることは簡単だが、オブジェクトの位置を得るには配列をスキャンしなければならない。内包的表現ではその逆で、オブジェクトの位置はすぐ分かるが、どの位置に何があるかは、オブジェクト全体をスキャンする必要がある。両方向での参照を高速に行うために、場合によっては、索引を作る必要が出てくる。
アクセスの容易さの他に、添字の空間の違いもある。外延的表現では添字が座標なので、2次元配列を使っている。一方、内包的表現では添字が識別子であるため、連想配列を使っている。つまり、添字の空間構造次第で、使うべきコンテナデータ構造が異なってくる。配列や連想配列を言語機能として備えている言語は多いが、添字空間が広大だったり連続的であるならば、R木のような構造が必要な場合もあるだろう。
オブジェクト指向のデータ表現では、オブジェクトを基準にデータが凝集されるため、素朴に設計すると内包的表現を選びがちではないかという気がする。しかし、それは空間上の現象を上手く表現することが難しいという問題がある。空間上で隣り合ったオブジェクトに作用するといった処理を書くには、将棋盤というオブジェクトを意識し、外延的表現を使う必要が出てくる。
昔、SQLiteをWebAssembly向けにビルドする例をGitHubに置いていたんだけど、 github.com
先月ごろフォークされて Uno.sqlite-wasm というリポジトリができていた。 github.com
Unoは、UWPアプリをiOSやAndroid, WebAssembly上で動かすプラットフォームらしい。
デモも公開されている。
- The SQLite + Entity Framework Core App, a demo of the combination of Roslyn, Entity Framework Core, SQLite and the Uno Platform to manipulate an in-browser database.
練習で作ったリポジトリだったので、ドキュメントやコメントはほぼ無かったのに、よく拾い上げてハックしたな、と思った。まあ、シンプルな構成だからドキュメントがなくても理解できるとも思う。
(当のsqlite-wasm, TypeScriptで書いた部分には微妙なこだわりを出していて、普通に型を付けたらポインタが全部number型になるのを避けるために、前回紹介したPhantom property patternを使っていたりする。)
TypeScriptは、JavaScriptエンジンの動的セマンティクス上に、静的な型システムのセマンティクスが重なっているものです。ここで、JavaScriptとしては正しく実行できても、TypeScriptの型システム上ではちゃんと型が付かないという場合もあります。ときには、TypeScriptで型がつくように大幅に書き換えないといけない場合も出てきたりして、そうなると大変です。それでも、TypeScriptの型システムは高度な機能を持っているので、大体の場合は、うまく表現してやると、JavaScriptらしい書き方のままで型をつけることができてしまいます。今回は、JavaScriptでよくある、プリミティブ値をそのまま取り回すパターンに型を付けたいと思います。
プリミティブ型を扱うプログラミングは、素朴でわかりやすいですが、型の考えからするとかなり悪いものです。こういうプログラミングを行うと、あらゆるデータを文字列で表す様子から、ときに”stringly typed”と揶揄されます。文字列は、表したいものはとりあえず何でも表現できるのでとても便利ですが、いろいろな種類のデータが一つの型で表されてしまうのなら、型が役立たずになってしまいます。すべてがstring
型のプログラムで、どうやってその文字列の中身がテキストなのか、URLなのか、メールアドレスなのかを判断するのでしょうか? 文脈を読み込んで察するか、ハンガリアン記法に回帰するか、さもなくばエスパーで当てるしかないでしょう。
この問題に対処するひとつの「まっとうな」方法は、プリミティブ値を直接使わず、適宜ラッパーオブジェクトを作り、その上でプログラミングを行うことでしょう。プリミティブ値ではなくオブジェクトを使えば、メソッドを追加することも容易です。しかし、実際にJavaScriptでそういうことが行われづらい原因として、ひとつはプリミティブ値をコンストラクタでラップするが手間だという点、ひとつは===
による同一性比較がオブジェクト型に対しては工夫を加えなければ意味上の同値性比較にならない点、ひとつは性能上の問題点、ひとつはシリアライズ・デシリアライズの自明さが失われる点が挙げられます。要するに、プリミティブ値をオブジェクトで包むのはわりとデメリットもあるわけです。
今ここに、この問題へのもうひとつの対処方法、幽霊プロパティパターン phantom property pattern を提唱します。このパターンを使うと、プリミティブ値の型を好きなだけ定義できる。つまり、言語組み込みのプリミティブ値を取り回すプログラムでありながら、各プリミティブ値を別々の型として取り扱うことができるようになります。
幽霊プロパティパターンでは、まず、次のような型を定義します。
export type Tag<X, R extends keyof any, Y> = X & { [rel in R]: Y }
x: Tag<X, R, Y>
は「xはXで、xのRはYである」というような意味になります。
次に、幽霊シンボルを定義します。
// This is a phantom symbol, which does not exist at run time declare const _unit: unique symbol export type unit = typeof _unit
_unit
は幽霊シンボルで、宣言しますが、実際には定義しません。_unit
の型はユニークシンボル型ですが、このままでは型に名前がなく使いづらいので、unit
というエイリアス名を付けます。
ここに定義したTag
型コンストラクタと幽霊シンボルを組み合わせると、プリミティブ値の性質を幽霊プロパティとして表現できます。
例として、角度の単位を幽霊プロパティとして付加した型を定義してみましょう。
export type Scale<X, U> = Tag<X, unit, U> export type Radian = Scale<number, "radian"> export type Degree = Scale<number, "degree">
ここで定義したRadian
, Degree
は両方ともプリミティブ値の数値を元とする型ですが、実際には存在していない[_unit]プロパティ
の型が異なるため、相互に代入不可能となっています。
{ const x: Degree = 30 as Degree const y: Radian = x // type error! console.log(x, y) }
いいですね。これを使って、たとえば三角関数や双曲線関数に単位をつけてあげるといい感じになります。
export const sin = Math.sin as (x: Radian) => number export const tanh = Math.tanh as (x: Radian) => number export const asin = Math.asin as (x: number) => Radian export const atanh = Math.atanh as (x: number) => Radian { const x = 30 as Degree const y = sin(x) // type error! console.log(y) }
弧度法で渡すべきところをうっかり度数法で渡すミスを、これで防げますね。 相互に変換する関数も用意してあげましょう。
// Ref: https://tauday.com/tau-manifesto const τ = 2 * Math.PI /** converts radian to degree */ export function toDegree(x: Radian): Degree { return (x / τ * 360) as Degree } /** converts degree to radian */ export function toRadian(x: Degree): Radian { return (x / 360 * τ) as Radian } { const x = 30 as Degree const y = sin(toRadian(x)) // ok console.log(y) }
例をもう一つ、今度はUnix時間とISO8601を扱ってみます。
今度は単位ではなくデータフォーマットの話なので、新しくdataformat
型を定義しています。
declare const _dataformat: unique symbol export type dataformat = typeof _dataformat export type UnixTime = Tag<Unit<number, "millisecond">, dataformat, "unixtime"> export type ISODateTime = Tag<string, dataformat, "iso8601"> export const now = Date.now as () => UnixTime export const toISODateTime = (t: UnixTime): ISODateTime => new Date(t).toISOString() as ISODateTime export const toUnixTime = Date.parse as (d: ISODateTime) => UnixTime export function isISODateTime(s: string): s is ISODateTime { return /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?Z$/.test(s) } { const t = 1514810096000 as UnixTime console.log(toISODateTime(t)) const d = "2018-01-01T12:34:56Z" if (isISODateTime(d)) { console.log(toUnixTime(d)) } }
UnixTime
型はデータフォーマットだけでなく、単位も幽霊プロパティで付加していますね。一口にUnix時間と言っても、実際にはミリ秒単位のものと秒単位のものが混ざっていることがよくあるのですが、こういう工夫が事故を防いでくれるはずです。
ISODateTime
型の方は、型ガード関数を用意しました。こういう関数を用意して使うほうが、直接as ISODateTime
でダウンキャストするよりも安全です。
interface Tag<X, R, Y> extends X { [rel in R]: Y }
とでも定義したいところですが、現状のTypeScriptではプリミティブ型を拡張できないため、やむなく交叉型 intersection type で表現しています。declare const _unit: unique symbol export type unit = Tag<typeof _unit, "name", "unit"> export type Unit<X, U> = Tag<X, unit, U> declare const _dataformat: unique symbol export type dataformat = Tag<typeof _dataformat, "name", "dateformat">
幽霊プロパティパターンを使うと、実行時コストに影響を与えることなく(ゼロコストで)、プリミティブ値にユーザー定義の型をつけることができるようになります。
2019/08/20追記: この記事を書いた時点では、先行事例があるということをちゃんと調査していませんでしたが、実は"Branding"と呼ばれて、それなりに使われている技法であることを知りました。(TypeScriptのソースコードでも使われています。)
以下の記事では、Brandingや、その変形であるFlavoringについて解説されています。 Need Flexible Nominal Typing for TypeScript? Use Flavoring, not Branding
数研出版の教科書『高等学校 社会と情報』(平成24年2月27日検定済、平成27年1月10日発行)の序編第II章では、「情報の特徴」と題して、情報とは何かとその特徴についての説明が行われているのだが、そこで行われている「情報の有無」の説明にいまいち納得が行かない。
情報の有無
16本のマッチ棒をテーブルの上に投げたとき,たいていは,図1のような乱雑な並び方になる。偶然にマッチ棒が,図2のように「SOS(または505)」の文字の形になる可能性もあるが,きわめて確率が低い。私たちが,図2を見たら,人が手で並べたと思うだろう。
この2つの状態(図1の並び方と図2の並び方)のちがい(差)は,何だろうか。私たちが一目見てわかるように,この2つには大きな差がある。そのちがい(差)が,情報である。
(『高等学校 社会と情報』14ページ)
並び方の乱雑な「テーブルに投げたマッチ棒」と、並び方に秩序があるように感じられる「人が並べた?マッチ棒」とを比較し、その差が情報であるとする「説明」は、理屈ではなく人間の直感に訴える説明であるため、理屈を気にしない人間ほど納得してしまうのではないかと思うけれども、しかしこの説明は変だ。
この説明は、乱雑な図1「テーブルに投げたマッチ棒」が〈情報がない方〉で、秩序だった図2「人が並べた?マッチ棒」が〈情報がある方〉だという想定で書かれているのではないかと思う。この説明をされて、何かが読み取れる方が〈情報がある方〉、何も読み取れない方が〈情報がない方〉だと受け取るのは、普通の感覚だと思う。
しかし、考え方によっては「左の方が情報が多い」と結論づけることもできる。どういうことか? こんな遊びを考えてみよう。
この遊びは2人でやる。片方の人間が、机の上のマッチ棒の状態をできるだけ少ない言葉で説明する。もう片方の人間は説明を聞いて、元の状態を見ずに、マッチ棒の状態を言葉だけから再現する。
図1と図2、それぞれでこの遊びをやるとどうなるだろうか。図1のマッチ棒の状態は乱雑で、素直に説明する言葉が見つからない。「マッチ棒が散らばっている」と言うだけでは図1の状態を精度よく再現することはできないから、マッチ棒1本1本について、その位置と向きを細かく説明する必要がある。一方、図2のマッチ棒の状態は秩序だっている。「マッチ棒が505の形に並んでいる」という言葉だけでも、ある程度再現可能だろう。マッチ棒の向きが問題だとしても、それぞれについて上下左右で指定すればいい。
結局、図1は図2よりも説明に必要な言葉が多いので、より情報が多いと考えられる。
こういう説明もできることを考えると、図2の方が〈情報がある方〉なのは一目瞭然だとするわけにはいかないはずだ。
乱雑に並んだマッチ棒は、意味のわかるパターンを含んではいない。しかし、意味のわかるパターンを含まないというのは、情報を持たないということではない。例えば、ジャングルの木々の並びにも、人間にとって直接意味のわかるパターンは含まれていないが、しかし、ジャングルの木々の並びを覚えることで、自分が今ジャングルのどこにいるのかを知ることができるようになり、ジャングルでの生活に役立てられるだろう。件の教科書は「情報」とは「意思決定の材料になるもの」(15ページ)だという考えを載せているが、その考えで情報を捉えるとしても、ジャングルの例で分かるように、人間が意図しない自然発生の差異もまた人間の意思決定の材料となる「情報」であるはずだ。
人間の作成したコンテンツを主に取り扱っていると「情報は人間が生む」という錯覚に陥りがちだが、情報を生むのは人間だけではない。宇宙のあらゆる存在が情報源となりうるのであり、それは人間がその意味を読解できるかとは関係がない。
lyrical-logical.hatenablog.com
読んでいて引っかかった部分について考えました。
この記事で僕が伝えたいのは、君が書くあらゆる関数には二組の入力と二組の出力があるってことだ。
間違いなく、InboxQueue の状態はこの関数の本物の入力だ。
この隠れた入出力にはちゃんとした名前があって、その名を「副作用」という
InboxQueue は、その関数スコープから参照可能な変数の一つに過ぎない。たまたまその関数の環境から触れるというだけで、入力というよりは、環境の中の mutable な変数の一つ、以上のことはないし、これを入力とは呼べない。これはプログラムの状態だ。
http://lyrical-logical.hatenablog.com/entry/2016/12/15/135831
問題のプログラムはこれです。
public void processNext() { Message message = InboxQueue.popMessage(); if (message != null) { process(message); } }
これはJavaのコード断片ですけど、断片だと分かりづらいので、JavaScriptでプログラム全体を書いてみることにします。
let Processor = { inbox: null, console: null, processNext() { let message = this.inbox if (message != null) { this.console = message } } } function main() { Processor.inbox = "hello" Processor.processNext() console.log(Processor.console) } main()
このコードのprocessNextメソッドは、元のコード断片より簡略化されているけど、議論の要点はおさえているはずです。
確かに、Processor.inboxはProcessor.processNextメソッドから参照可能なmutableプロパティですが、同時にmain関数からも参照可能です。このことが、mutableプロパティを一種の「共有メモリ」として使った2関数間の通信を可能にしています。
プロパティ経由の値の受け渡しが、「プログラムの状態」としてプログラミング言語のセマンティクス内で説明できる動作だとしても、Processor.inboxはProcessor.processNextへの入力となっていると表現して問題ないはずです。
このコード例から、次のことが言えます:
副原因と副作用は対称的で、Processor.inboxはProcessor.processNextにとって副原因の源ですが、mainにとっては副作用の対象です。つまり、副原因があるとき、対になる副作用も現れ、大域的に見れば両者は同一の現象です。
言いたいことは分かる。暗黙的に環境内の変数を参照するよりも、陽に変数を取るようにしたほうがいい。
public void processNext(InboxQueue inboxQueue) { Message message = inboxQueue.popMessage(); if (message != null) { process(message); } }http://lyrical-logical.hatenablog.com/entry/2016/12/15/135831
環境に依存した関数の定義には注意すべし、それは一般に言って正しいことだと思うし、反論するつもりはない。しかしそれを「関数型プログラミングって何?」という文脈で話すのは、違和感が強い。
http://lyrical-logical.hatenablog.com/entry/2016/12/15/135831
ここで言っている「環境」って、何を指しているんでしょうか? グローバル環境のことでしょうか? それとも、関数の引数ではなく、ブロックスコープに宣言された変数を、環境内の変数と呼んでいるのでしょうか? あるいは、次のようなクロージャーで、関数g内で参照されているxはgの引数ではないわけですけど、こういう場合も「暗黙的に環境内の変数を参照する」に入るんでしょうか?
function f(x) { return function g(y) { return x + y } }
しかし * あらゆる * 関数に二つの入力がある、と記事では主張している。つまり上のコードでは不足だろう。
ならもうちょっと別の書き方をしよう。コードは疑似的なもので、こんな API がある言語は知らない。public void processNext(Frame frame) { Message message = ((InboxQueue)frame.getEnvironment.getVariables.searchVariable("InboxQueue")).popMessage(); if (message != null) { process(message); } }あるいは、InboxQueue の状態をある種の precondition としてとってもいいかもしれない。
public void processNext(InboxQueueState state) { // state を使って何かしたいときもあるかもしれない。以下は一例だ。関数の意味は変わる。元記事では関数の前提条件について何も触れられていないので、これは自分が勝手に加えたものだ。popMessage は blocking API かもしれないし、そうであればこのような前提条件は妥当でない。 if (state.isEmpty()) throw new IllegalArgumentException("InboxQueue must has some elements."); // これは assert を書いて precondition をコード上で陽にしているのと大した差はない。 assert(!state.isEmpty()); Message message = InboxQueue.popMessage(); if (message != null) { process(message); } }一歩譲って、これらをもってして、あらゆる関数には二つの入力がある、という主張を受け入れたとしよう。しかしそれは「関数プログラミングにとって」大事なことなんだろうか。
http://lyrical-logical.hatenablog.com/entry/2016/12/15/135831
このくだりはほとんど意味が分かりません。「関数型プログラミングって何?」の酷さを示すために、書かれたとおりにやってみて酷さを示すというにしては、そもそも書いてもいないことを突然やりだしたように見えます。「上のコードでは不足だろう」と思った理由もはっきりしなければ、それで例に出した「別の書き方」をそう書いてみたワケも、書かれていません。
“I put it to you that every function you write has two sets of inputs and two sets of outputs.” という一文中の “every” という一語が気にくわないということ以上ではないのであれば、よく分からない例なんか出さずとも、記事最初の例
public int square(int x) { return x * x; }
には副原因も副作用もないよね、と指摘すれば済むのでは、と思ってしまいます。
でも、ただ「 * あらゆる * 関数に」って書き方じゃなくてevery function you writeなんだし、自分はこれは記事に食い付かせる「釣り」のたぐいの表現なんじゃないでしょうか。まあ、こういう正確さに欠けた表現はちょっと気に障るってのは分かります。
これで、この関数は入力(や出力)を隠し持たなくなった。
本当にそうだろうか。上の主張は関数内で読んでいる関数が純粋であるという仮定が成り立つときに限る。"getSchedule" "programAt" が純粋でないなら、そこには状態が潜んでいる。関数内で呼び出している関数のスコープにある状態に触れている、依存している可能性がある。
http://lyrical-logical.hatenablog.com/entry/2016/12/15/135831
もう少し前に、こう書いてあります。
この関数には現在時刻 (new Date()) という入力が隠れている。
http://okapies.hateblo.jp/entry/2016/12/15/021550
"getSchedule" "programAt" が純粋でないなら、「この関数には現在時刻 (new Date()) という入力が隠れている」という部分で一緒に副作用(あるいは副原因)のある関数としてリストアップされなければ、話の構造上不自然です。ここでリストアップされていない以上、 "getSchedule" "programAt" は純粋だということが暗に示されてます。それを、陽に示されていないからといって「"getSchedule" "programAt" が純粋でないなら」と言い出すのは、揚げ足取りに見えます。
引数にのみ依存し値を返す、同じ引数に対して常に同じ値を返す関数であるという一般的な説明でよいだろう。
http://lyrical-logical.hatenablog.com/entry/2016/12/15/135831
「引数にのみ依存し値を返す、同じ引数に対して常に同じ値を返す関数」という定義には問題があります。この定義では、副原因を持たないが副作用を持つ、次のような関数を除外できないのでダメです。*1
let a = null function out(x) { a = x return x }
結論。住井先生がわざわざ記事書いてくれてるんだから、まずそれを読もう。読めば訳された記事がイマイチなのは分かると思う。
http://lyrical-logical.hatenablog.com/entry/2016/12/15/135831
“A functional language actively helps you eliminate side-effects wherever possible, and tightly control them wherever it's not.”って、住井先生の「関数型言語とは、……関数型プログラミングを推奨・支援するプログラミング言語」「(関数型プログラミングとは)副作用をできるだけ(あるいは全く)用いず、式や関数で計算を表すプログラミングスタイル」ってのとほぼ同じこと言ってますよね。まあ、住井先生の記事の方はリファレンスがちゃんと張ってあるのがいいと思います。
*1:こういう説明が簡単にできるようになるので、「副作用」と「副原因」を区別するのは有意義だと思います。
この記事は2016年当時の状況を書いています。その後のバージョンアップで、Windowsでのフォントレンダリングは改善され、ガンマ補正周りのエラーはなくなっているようです。当時の状況を資料として残しておきますが、記事を参照する場合はご注意ください。
游ゴシック体は単に細いから薄いのではなく、ガンマ補正が2重、3重に掛かっているために、グレーが本来よりも明るくなりすぎている。ガンマ補正を逆に掛けると、正常な表示になる。
Windowsでは游ゴシックがかすれて見える。細字だと薄くて読みづらいから、より太いウェイトを指定しろという話もある。(Windowsで游ゴシックが汚いのは、結局誰が悪いのか? | Cherry Pie Webなど)だが、かすれて見える原因は、ウェイトが細すぎるからではない。
例えば、本文に游ゴシックを使っているWIREDの記事(「癌」という名のドラゴン──父はゲームをつくった。死にゆく息子のために | WIRED.jp)のキャプチャ画像を見てほしい。
注目してほしいのは、ただ文字が薄いというわけではなく、線によって濃さが違うということだ。曲線の多い仮名に比べて、ピクセルに沿った直線の多い漢字の方が黒くみえる。
また、アプリケーションによって字のかすれ具合が違う。たとえば、次の画像は游ゴシックを同じウェイト、同じポイント数で、それぞれFirefoxとメモ帳を使って表示したものだ。
どちらも薄くかすれて見えるが、メモ帳の方がより薄く見える。
Windowsのフォントレンダリングは、ただ薄いのではなく、線によって濃さが違う。その原因は、ガンマ補正が適切に行われていないことだ。
ガンマ補正とは何かを説明するために、色の仕組みから説明する。
多くの人が知っているとおり、コンピューターでは色を数値で表したものを処理する。色を数値で表す方法には色々あるけれども、いちばん有名なのは、RGBカラーコードだろう。たとえばCSSでは、カラーコードを使って、黒はrgb(0, 0, 0)、白はrgb(255, 255, 255)とも表せる。これは、色を構成するR(赤), G(緑), B(青)の三原色それぞれの輝度を、0から255までの数値で表現したものだ。
しかし、ここから先の話はあまり知られていないことだと思う。多くの人は、rgb(255, 255, 255)の半分の明るさのグレーは、rgb(128, 128, 128)だと思っている。だけど、それは間違いだ。実は、rgb(128, 128, 128)はrgb(255, 255, 255)の2割ほどの明るさしかない暗いグレーであり、本当に半分の明るさになっているグレーはrgb(188, 188, 188)なのである。*1
これには、ブラウン管モニターの特性に関する歴史的事情が関わっているのだけれども、深くは立ち入らない。大事なのは、rgb(128, 128, 128)が半分の明るさだと思ってプログラムを書くと、グレーが暗くなってしまうということだ。だから、暗くなる分を考慮して、明るめの画像を表示しないといけない。そのような補正処理を、「ガンマ補正」と言う。
おそらく、Windowsのフォントレンダリングにおいてもガンマ補正が行われているのだが、どういうわけかガンマ補正が多重に掛かっているようだ。つまり、グレーを明るくする処理を重ねたためにグレーが明るくなりすぎている。(rgb(128, 128, 128)を補正してrgb(188, 188, 188)になるはずが、rgb(223, 223, 223)やrgb(240, 240, 240)になっている。)
参考として、GIMPのレベル補正機能を使ってガンマ補正を逆向きに(グレーが暗くなるように)行った画像を載せる。指定した0.46, 0.21というのは、ディスプレイのガンマ値2.2の逆数と、その2乗だ。
字のかすれが解消され、全体が同じ濃さの文字になっているのが分かるだろうか。この結果から、ブラウザーに関してはガンマ補正が2重に、メモ帳に関しては3重に行われていると考えられる。(※このことに関して追記あり)
游ゴシック細字は本来この程度の黒さで表示されるべきなのであり、ただ細すぎるから薄くて読みづらいという話ではない。太くすると読めるようになるのは、グレーの領域が少なく、ガンマ補正が適切でないのが誤魔化されるだけであり、Windowsのフォントレンダリングが適切でないことには違いない。将来的にはガンマ補正を修正して、細い字もムラなくちゃんと表示できるようになるように改善してほしいと思う。
游ゴシック、かすれて見える理由はガンマ補正が間違っているからなので、黒背景に白字だと逆に太くなる。 pic.twitter.com/mwXZmFV60U
— Ryusei (@mandel59) 2016年11月10日
ブックマークコメントでも意見を頂きましたが、メモ帳のようなGDIでClearTypeを使ってレンダリングしているケースに関しては、ClearTypeの設定によって表示が変わるようです。自分もメイリオ初期設定から変更していたように思います。なので、3重に補正が掛かっているというのは誤解で、たまたまそう見えるガンマ値が設定されていただけであるようです。
*1:色空間がsRGBの場合
以前、言語の完全性について言及した。今回は引き続き、言語の完全性について考える。
フレーゲは未定義の式の存在を「言語の不完全性」(einer Unvollkommenheit der Sprache)とみなしていた。論理学者のフレーゲにとって、表現の「意味」(Bedeutung; その記号があらわしている事物。表記対象 denotation や言及対象 referent に相当すると考えられる)が確定していることは重要なことであった。表現の「意味」は、ちょうど1つでなければならず、それより多くても、少なくてもいけない。*1そのような多義的ないし無意味な表現は論理的誤謬のもととなるので、学問から排除するべきだと考えた。
フレーゲの提案した「約定」(Festsetzung)とは、そのような「言語の不完全性」を排し、言語を完全化する方法である。ある表現に「意味」が複数考えられる場合や「意味」が考えられない場合には「約定」を行うことで、あらゆる文法的に正しい表現の「意味」をただひとつに定める。簡単に言えば、「意味」がないなら(「意味」が多いなら)、「意味」を決めてやればいいというようなことだ。
数学では「√」という記号は正の平方根を表すと決めることによって、「」がだけを表すとし、をも同時に表すことを退けているが、これも一種の「約定」だと言える。「言語の不完全性」を「約定」により避け、あらゆる表現の「意味」をただひとつに確定した「論理的に完全な言語」(einer logisch vollkommenen Sprache)をフレーゲは構想し、それを「概念記法」(Begriffsschrift)と呼んだ。フレーゲは、「言語の完全性」を達成するために、「概念記法」に次の要求を行った。
論理的に完全な言語(概念記法(Begriffsschrift))に対しては、すでに導入された記号から文法的に正しい方法によって固有名として構成された表現はすべて、実際上ある対象を表示することと、いかなる記号もそれに対する意味が保証されることなしに新たに固有名として導入されることはないという二つのことが求められている。[1]
ここで挙げられている要求は、おおむね〈構成性〉と〈原子確定性〉に相当する。(これらの用語は以前 Referential Transparencyの代わりに使える概念案 - Ryusei’s Notes (a.k.a. M59のブログ) で導入したものだ。)「概念記法」を規定する「約定」すべてに〈構成性〉と〈原子確定性〉を要求することで、「概念記法」全体の「論理的な完全性」=〈確定性〉を実現できる。*2
フレーゲの「約定」は表現の「意味」を唯一に定めることに主眼があるため、個々の「約定」に論理上の根拠は存在しない。むしろ、論理上の根拠が与えられないからこそ、約定によって表現の意味を決めるというのだろう。「約定」に論理上の根拠がなくとも、その「約定」が〈構成性〉と〈原子確定性〉を満たす形で行われるのであれば、どう「約定」しようとも「概念記法」全体の〈確定性〉は保証され、矛盾が生じることはなく、論理上は問題がない。
例えば、フレーゲは解析学の記号の「不完全性」を示す例として発散級数(収束値を持たない級数)を挙げ、発散級数はは数0を表すと「約定」することによって、この「不完全性」を排除することに言及している。この数0による「約定」はあくまでも例で、根拠があると言えないが、〈構成性〉と〈原子確定性〉を満たすどのような「約定」を行っても、矛盾が生じることはない。
[1] フレーゲ, ゴットロープ (1986) 「意義と意味について Über Sinn und Bedeutung」(土屋 俊 訳), 坂本百大 編『現代哲学基本論文集』 1, p. 26, 勁草書房.
ドイツ語の表現はGottlob Frege. Über Sinn und Bedeutungから適宜引用
Windows 10を導入する上でやったこと
液晶の白が青かぶりしている感じだったので、ディスプレイの詳細設定から色設定を行う。
更新とセキュリティから、開発者向け機能に関する設定を行う
ソフトウェア開発に使う各種ツール群をコマンドラインからインストール
PackageManagement+chocolateyで入れるとデフォルトで改行コードの変換が行われる設定になるのでgit config --global core.autocrlf=false
しておく。
{ "editor.tabSize": 2, "editor.renderWhitespace": true, "files.eol": "\n", "terminal.integrated.shell.windows": "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe" }
Suica専用自販機。
— いし@名誉駅長35ヶ月目 (@mk_ishi) 2016年7月15日
どんどん進めていけばいいし、
通常の自販機を流用するのも全然いい。
たださ、
なんでコイン投入口跡に小銭のイラストを残したの?
飲み物買おうとした外国人、英語の説明ないから、お金入れようと四苦八苦してたぞ。 pic.twitter.com/qIja6ba6Bx
あと、Suica専用自販機のコイン投入口の上の点字、
— いし@名誉駅長35ヶ月目 (@mk_ishi) 2016年7月15日
たぶん"コイン"って書いてある。
視覚障害者のことを考えたら、コインが投入できないここに、コインって点字を残さないでしょ。https://t.co/PKCv57C7U7 pic.twitter.com/6ceHmw1wgp
あの酷い、残額を見せる気のない自動改札機を改良もせずに展開してるJR東日本に期待する方が悪いとは思ってるけど、
— いし@名誉駅長35ヶ月目 (@mk_ishi) 2016年7月15日
訪日外国人や視覚障害者にたいしての配慮がいかないのはさすがに放置できない。
この話を見た時、これはまさに「形骸化した記号」のよい例だろうと思った。ナンセンスな「電子署名」の話よりも、それが形骸であることがずっと分かりやすい。
普段から自販機を使っている大多数の日本人にとって、それがコイン投入口だということを認知するためにコインの絵や点字は必要ではなく、無意識に見過ごされた記号であったのだろう。だから、実際に困る人が現れるまでは、誰も気づくはずがなかった。
それで、教訓として得るべきなのはなんだろうか。マイノリティーへの配慮を充実させること? まあ、それはそうだろう。多様性を持つ利用者全般に対して不都合のないデザインであるか、よくテストを行うべきだと言える。アクセシビリティのガイドラインを守り、マイノリティーを尊重し、適切なテストを行った後にプロダクトを出すのが理想だ。問いたいのは、理想を実現させるにはどうすればよいのかということだ。
あらゆるマイノリティーに対してアクセシビリティ上の困難がないかテストをするには多大なコストが掛かる。それは必要なコストだ、と頭で分かるとしても、感情が付いてこない。マジョリティーはマイノリティーに対する意識を高めなければならないのだけれども、それはアクセシビリティのガイドラインを頭に叩き込むだけでは成しようがない。必要なのは、ルールの遵守というよりも、記号を多様な観点から見ることができる柔軟さだ。
記号の不完全さへの意識を高めるのに、笑いは重要な役割を果たしうる。私たちは記号を信用し、時に記号に裏切られる。記号の解釈には文化による差異があり、それによって起こる勘違いは、記号が引き起こす悲喜劇だ。記号はコミュニケーションのなかだちだけど、それが勘違いの種であり、常に不完全さを孕むことを認めよう。未知の存在との交流は常に勘違いの連続だ。私たちは記号と、記号が引き起こす勘違いを互いに笑いながら、少しずつ乗り越えていくしかない。異文化交流とは、寛容性を前提としなければ成し得ないと思う。
東京メトロの多言語化戦略、全部の言語にふりがなが付いていて賢い
— Ryusei Yamaguchi (@mandel59) 2016年7月15日
全部の言語にふりがながあるから、ハングル表示の時に日本人が読めないというクレームを無効化している、神対応か
— Ryusei Yamaguchi (@mandel59) 2016年7月15日
ドラえもんの絵の広告で見ただけでインプリメンテーションは確認していないが、絵だけで神デザインとわかる
— Ryusei Yamaguchi (@mandel59) 2016年7月15日
ちなみにこれね。全言語にふりがな。 pic.twitter.com/C6kmxVG6eQ
— Ryusei Yamaguchi (@mandel59) 2016年7月15日
ルビ(振り仮名)が振ってあると、すごく日本っぽい感じがする。ハングル一色の画面を見れば、異形の文字を見慣れない人には忌避感を与え、ここは日本だぞと文句を付けたくもなるっていう人が出てくるんだろうけれども、ハングルに振り仮名するだけで、そういう人にとっても、なんだ日本語じゃないかと思えてくるのではないか。たぶん。まあ、それでも文句を付ける人は付けるんだろうけれども。
ルビは、昔から漢字と仮名を併用してきたからこそ生まれた、日本独特の組版文化だと言える。もちろん、発音を併記するのは中国語学習用のテキストとかでもやることではあるのだけれども、日本語のようにルビを常用する文化は他にないだろう。漢字と仮名という複数のチャンネルを使って情報を流すことで、字義と音価、あるいは意味と意味が新しい形で結びつく。そのことが、言葉を新しい視点から眺めることを教えてくれる。
ルビの欠点として、ルビは小さい。視力に自信がない人は、やっぱり平仮名の大表示も欲しいって思うだろう。そして、ルビを振ると画面が煩雑になる。大きな表示スペースがないと難しい。万人にとって良い画面を設計するのはほぼ不可能なことで、どうしたって切り捨てが生じてしまう。液晶ディスプレイによる時分割表示は、多言語対応の万能薬ではない。
そもそも、公共のディスプレイに表示しようとするから、万人が読める表記という難題を解かなければならないのであって、一番いいのは、個々人に最適化された案内表示がなされることだろう。スマートフォンに表示する分には、他人の目を気にすることなく、自分の都合のよい表示方法に設定できるはずだ。案内情報を局所的に配信する仕組みは絶対に必要だと思うのだけれども、誰か真剣に取り組んでくれないだろうか。
今回の裁判の要旨は「いわゆる花押を書くことは,民法968条1項の押印の要件を満たさない」ということですが、その理由を抜き出してみます。
3 原審は,次のとおり判断して,本件遺言書による遺言を有効とし,同遺言により被上告人は本件土地の遺贈を受けたとして,被上告人の請求を認容すべきものとした。
http://www.courts.go.jp/app/hanrei_jp/detail2?id=85930
花押は,文書の作成の真正を担保する役割を担い,印章としての役割も認められており,花押を用いることによって遺言者の同一性及び真意の確保が妨げられるとはいえない。そのような花押の一般的な役割に,a家及びAによる花押の使用状況や本件遺言書におけるAの花押の形状等を合わせ考えると,Aによる花押をもって押印として足りると解したとしても,本件遺言書におけるAの真意の確保に欠けるとはいえない。したがって,本件遺言書におけるAの花押は,民法968条1項の押印の要件を満たす。
4 しかしながら,原審の上記判断は是認することができない。その理由は,次のとおりである。
花押を書くことは,印章による押印とは異なるから,民法968条1項の押印の要件を満たすものであると直ちにいうことはできない。
そして,民法968条1項が,自筆証書遺言の方式として,遺言の全文,日付及び氏名の自書のほかに,押印をも要するとした趣旨は,遺言の全文等の自書とあいまって遺言者の同一性及び真意を確保するとともに,重要な文書については作成者が署名した上その名下に押印することによって文書の作成を完結させるという我が国の慣行ないし法意識に照らして文書の完成を担保することにあると解されるところ(最高裁昭和62年(オ)第1137号平成元年2月16日第一小法廷判決・民集43巻2号45頁参照),我が国において,印章による押印に代えて花押を書くことによって文書を完成させるという慣行ないし法意識が存するものとは認め難い。
以上によれば,花押を書くことは,印章による押印と同視することはできず,民法968条1項の押印の要件を満たさないというべきである。
読みづらいので、箇条書きにして原審の判断と最高裁の判断を整理してみます。
原審の判断:
原審では押印の要件をどのように考えていたのかが抜けているので、これだけでは妥当な論証にはなっていません。原審の判決文を確認する必要がありそうです。
最高裁の判断:
この論証は妥当な論証ですが、結論を導くのに必要なのは(5.)の〈(5-1.)と(5-2.)をともに満たす⇔押印の要件を満たす〉という趣旨の命題と(6.)の〈花押を書くことは(5-2.)を満たさない〉という趣旨の命題だけです。(3.)と(4.)は、それが否定されると結論も否定されるような命題です。
論証自体は妥当ですが、そこに挙げられている前提(5.), (6.)は妥当なのでしょうか。
(5.) の主張のために「最高裁昭和62年(オ)第1137号平成元年2月16日第一小法廷判決」が参照されていますが、この裁判の要旨は「自筆遺言証書における押印は、指印をもつて足りる」ということです。こちらも、その理由を抜き出してみます。
自筆証書によつて遺言をするには、遺言者が遺言の全文、日附及び氏名を自書した上、押印することを要するが(民法九六八条一項)、右にいう押印としては、遺言者が印章に代えて拇指その他の指頭に墨、朱肉等をつけて押捺すること(以下「指印」という。)をもつて足りるものと解するのが相当である。けだし、同条項が自筆証書遺言の方式として自書のほか押印を要するとした趣旨は、遺言の全文等の自書とあいまつて遺言者の同一性及び真意を確保するとともに、重要な文書については作成者が署名した上その名下に押印することによつて文書の作成を完結させるという我が国の慣行ないし法意識に照らして文書の完成を担保することにあると解されるところ、右押印について指印をもつて足りると解したとしても、遺言者が遺言の全文、日附、氏名を自書する自筆証書遺言において遺言者の真意の確保に欠けるとはいえないし、いわゆる実印による押印が要件とされていない文書については、通常、文書作成者の指印があれば印章による押印があるのと同等の意義を認めている我が国の慣行ないし法意識に照らすと、文書の完成を担保する機能においても欠けるところがないばかりでなく、必要以上に遺言の方式を厳格に解するときは、かえつて遺言者の真意の実現を阻害するおそれがあるものというべきだからである。もつとも、指印については、通常、押印者の死亡後は対照すべき印影がないために、遺言者本人の指印であるか否かが争われても、これを印影の対照によつて確認することはできないが、もともと自筆証書遺言に使用すべき印章には何らの制限もないのであるから、印章による押印であつても、印影の対照のみによつては遺言者本人の押印であることを確認しえない場合があるのであり、印影の対照以外の方法によつて本人の押印であることを立証しうる場合は少なくないと考えられるから、対照すべき印影のないことは前記解釈の妨げとなるものではない。そうすると、自筆証書遺言の方式として要求される押印は拇印をもつて足りるとした原審の判断は正当として是認することができ、原判決に所論の違法はない。論旨は、採用することができない。
http://www.courts.go.jp/app/hanrei_jp/detail2?id=52210
平成元年の判決の判断:
(5.)は(7.)を参照していて、ほとんど同じ表現であることがわかります。(7.)の〈(7-1.)と(7-2.)をともに満たす⇔押印の要件を満たす〉という趣旨の命題は、(8.)の〈指印は(7-1.)を満たす〉、(9.)の〈指印は(7-2.)を満たす〉という趣旨の命題と合わせて、(結論3.)を妥当に導くための前提になっています。
(7.)が指印が印章の代わりになることを主張する際に考えられた前提であるのに対し、それを今回の判決の(5.)は逆に使われていて、花押が印章の代わりにならないことを主張するための前提になっていますが、主張(5.)自体は妥当で「押印の要件」つまり押印であると認められる必要十分条件になっていると思われます。そうすると、問題になるのは(6.)です。
(6.)は単に原審における前提(1.)の「印章としての役割も認められており,」を否認しているだけのように見えます。(原審の判決文は確認できていないので、原審で認められた「印章としての役割」が具体的にどのような役割を指しているのかははっきりしませんけれども。)そして、その前提にさらなる理由は与えられていません。
結局、判決文を読んで分かったのは、最高裁判所は「我が国において,印章による押印に代えて花押を書くことによって文書を完成させるという慣行ないし法意識が存するものとは認め難い」という判断を行ったが、その判断には全く理由が与えられていないということでした。なぜ、こんなよく分からない判決文が許されているんでしょうか。「印章による押印に代えて花押を書くことによって文書を完成させるという慣行ないし法意識が存する」かどうかについて、十分審議が尽くされたのでしょうか。審議するまでもなく自明だという認識なんでしょうか。そこら辺が、よく分かりませんでした。