【C#】デバッガを非表示なメンバを作成する
デバッガに表示するためにToString()メソッドを実装したりDebuggerDisplay属性つけたりしますが、たまにフィールドとプロパティーが同じで無駄に冗長になることがあります。
こんな時です
private long offset;
public long Offset { get { return offset; } set { offset = value; } }
同じ結果を返す時は冗長になるのを避けるために
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
属性を付ければいいです。
ただ、privateなものを全て隠すようなことは推奨しません。
そもそもデバッガウィンドウはprivateな状態を覗くものだと思っているので、あまりに隠し過ぎるとデバッガウィンドウがガラクタになってしまうでしょう。
【VisualStudio】 デバッガで結果ビューを表示しようとするとエラーになる
IEnumerableを継承した独自クラスを作成しているとたまに結果ビューでデバッガがエラーを吐いたりすることがあります。
おかしいなと思ってforeachループを回してみるとなんの異常も見当たらず。エラーを吐かないバグはプログラマの天敵です。
例えば無限ループにはまっていたりすれば一瞬にして原因究明が出来ていいのですが(よくない)、デバッガのほうのエラーはトレスできません。
これはGetEnumerator()の明示的実装と暗黙的実装がクラスに混在している場合に起きることで、
デバッガは明示的実装を参照し
foreachは暗黙的実装を参照するからです。(コンパイラが選択?)
なぜだかは分かりませんが。
したがってforeach出来て結果ビューがおかしいときは明示的実装と暗黙的実装の差異を取り除くか、どちらかに統一してあげればよいでしょう。
【雑記】優れた関数とは Part2
【雑記】優れた関数とはの続きです。
つまり全てのデータが圧縮できるように自分より小さなデータの器を手に入れると、はじき出されるデータが必ず存在するのである。
ではどうして圧縮ソフトが存在し、多くの圧縮アルゴリズムが考案されているのだろうか、疑問が浮かぶだろう。
それは人間が特徴的なデータ界に存在しているからである。いや、もっと適切な言い方に言い換えよう。
人間が人間の為に作ったデータフォーマットが必ず特徴的になるのである。
つまり、特徴的ではないデータを捨てればいいのだ。人間が美しくないと思う画像は排除すればいいのだ。そういったデータが、はじき出されてどんなに膨大なデータ量になろうと「あとは野となれ山となれ」の精神で切り捨てればいいのだ。
先ほどのグラフを引用すれば
灰色の範囲は人間にとって不要であると人間が定義して、圧縮と言っているのである。
ここでそろそろ本題に戻って、この記事を書き始めた優れた関数とは何か。結論を示そう。
それはひとえにどれだけ人間の思考に近いのか?
これが私の導き出し結論である。
言語とは物事を伝える手段であり、この地球に存在しているもの以外にも無限に存在する。それが人間の作り出した言語よりどれだけ効率的であって、それを理解できている関数が存在しても、人間が人間の為に作った自然言語を理解できない関数は私たち人間から非効率な関数だとレッテル張りをされてしまうのである。
つまり、人間の自己満足、エゴであるがこれがの本質なのである。
では人間が考える最高の関数というのはなんだろうか。それは人間自身である。
つまり人間を模倣したニュートラルネットワークは最高の関数を作成するうえで非常に的を射たアルゴリズムなのではなかろうか。
最後に一つ疑問を投げかけてこの記事を締めようと思う。
人工知能が進化して、人間の及ばぬ崇高で論理的な思考を有したとき、それは人間にとって本当に効率的な関数となるのであろうか?
【雑記】優れた関数とは Part1
全ての動作は関数である。おもむろにこう書きだしてみよう。
時間ベースで考えれば、同じ解を返す関数なら素早いほうが優れた関数であると言える。
ここでは純粋に入力と出力のみにフォーカスをあてることとしよう。
では次に示す二つの関数はどちらが優れているだろうか?
答えは"比べられない"です。全てにおいて万能な関数などありません。
ではデータの可逆圧縮について、と前提条件を与えることにする。
するとほとんどの人間はAと答えるだろう。でも本当にそうだろうか?
全てのデータを変換したときどのようなデータ長になるかグラフを用意した。
グラフの縦軸は変換後のデータ長、横軸は無限にあるデータ。
(データは無限にあり、そもそも直線状に並べられるものではありませんが、ここでは一次元に射影したものとしてみてください。)
と見ると、
A関数は特徴的なごく一部なデータは圧縮されるが、その他の大多数はデータ長が増えるのである。
B関数は全てのデータにおいてデータ長は増減しないのである。
それらを全て足し合わせるとA関数もB関数も圧縮性能は全く同じなのである。
わかりやすく説明しよう。
つまり全てのデータが圧縮できるように自分より小さなデータの器を手に入れると、はじき出されるデータが必ず存在するのである。
少し長くなったのでページを分けます。次ページも読んでね。
【シンギュラリティ(技術的特異点)】人工知能は人類の後継者として新人類となれるのか
シンギュラリティ(技術的特異点)とは、
人間が人間以上の知能を持つ機械を作れた時、
- 人間は自分以上の知能を持つ機会を作れる。
- 作られた機械は人間ので出来ることは(人間以上の知能を有するため)出来る。
- 1,2より機械は自分の知能以上の機会を作ることができる。
これを繰り返すことで爆発的指数関数的な機械の知能高騰が起こる。
人間の知能では例えば(人間よりも知能が低い)イルカが数年後にどれだけ知能が進化するかは予測できるが、人間以上の知能を有する機械の知能上昇は予測することすらできない。
これが爆発的な知能上昇と抽象的に言われる所以である。
凡俗はこれくらいの理解があれば上出来である。
しかし私たちプログラマはもっと詳しく理解している必要がある。
知能とは何なのか?人間をすべてに上回る知能ってどう判別するの?そういった疑問に答えられないようでは、世の中の記事に乗せられただけの凡俗と変わりないのである。
現在の人工知能を説明するには人間の思考回路を理解する必要がある。
それは自分が物事を考えるときにどういった理論の積み重ねで結論を導き出すかのフローを明確にすることでは"ない"。「無矛盾な公理的集合論は自己の無矛盾性を証明できない(※1)」のと同様に「己の思考の中で己の思考回路は理解できない」。思考回路を理解するためには思考回路を物理的に三者視点で見る必要がある。
つまり生物学での人間の脳を理解しなくてはならない。人間の脳はシナプス同士の電気的つながりなのである。それは機械における集積回路のようなもので、シナプスの挙動は一定以上のシナプスからの電気信号が流れた時にシナプスは他のつながったシナプスに電気信号を流すといった単純な挙動の集まりなのである。
それをプログラムで実装したのがニュートラルネットワークであり、人間の脳を模倣したものであるから知能を比較することもまた(他に比べて)容易なのである。
(ニュートラルネットワークの説明とアルゴリズムの話は(長くなると思うので)ここでは割愛して次の機会に解説します。)
シンギュラリティを迎えるにあたってほとんどの人間は不要になる。労働力が過剰になり、人間個人の労働力は無価値に収束していくのである。もちろん無価値な人間は淘汰されることは当たり前で、それが人類の進化である。
その生み出された機械が人間とは違う種属(最高知的生命体)として地球を牛耳るのか、人類が生み出した正当な後継者として新人類として元人間と置き換わる子孫となりえるのか。人類が人工知能の進化を手放すのか。
ともあれシンギュラリティ前後の時世で弱者とならないためには、労働力を使う強者として生きるため、ニュートラルネットワークに精通することがプログラマの急務であると私は考える。
※1.詳しく知りたい人はラッセルのパラドックスを調べてください。
【Linq】LinqがPull型の特性を生かしきれていない理由
Linqは非常に有力な考え方として世界に普及しましたが、ReactiveExtensionが普及した今考えると、非常に"もったいない"考え方であると私は思う。
理由を語るためにLinq(Pull型)とRx(Push型)のフローを可視化してみる。
これで分かるようにMoveNext命令は連続して実行する際は無駄であり、Rxに完全に置換できるのである。
ここでPull型が非効率的であると言っているわけでないことに留意していただきたい。
Pull型のPush型にない長所としては、
- 次の値を取得する時期をカスタムできる
- 取得命令のカスタマイズができる
これらの特徴を生かし、Linqの実装をサポートするのならば、
int GetCount()
void Move(int index)
T GetValue()
とすれば、今までのようなLinqの機能は包括され、Take()やSkip()などのインデックス操作は非常に高速化され、今まで出来なかった並べ替え操作も高速に実装できる。
不安要素としては初めにGetCount命令をするため、Countを保持しないデータ構造では
非効率になる場合があることだ。しかしCountを保持しとけばよい事である.。保持できないデータ型としてはLinkedListがあるが、LinkedListの操作はその他のコレクション型と大きな差異があり、それは例外的に処理することが望ましいだろう。
インデックスアクセスできないデータ型では非効率的になると思われるだろうが、二分木構造ではlog(N)で取得できるし、相対インデックスの絶対値が小さいならMoveNextのような処理を分岐すればよいのである。
【雑記】関数名を考える時間が既に人生
プログラマの頭を悩ませるのは、アルゴリズムやデータ構造などではなく、往々にして関数名である。と私は思う。
目的の関数を表すいい英単語を探すのはなかなかに面倒くさい作業だ。日本語ですら数語で関数の説明をするのは骨が折れるのに。
後で意味がわからない関数名にするぐらいなら、関数を説明するために長い関数名にするくらいな、それこそ短く適当な名前にしてしまったほうがいい。(言い過ぎ?)
関数名に最適な英単語を見つけてもその英単語自体忘れてしまっていて、次ライブラリを使うとき時間が空いたならば結局全ての関数を精査しなくてはならなくなる。
プログラミング時に自分の頭がハッシュ構造の役割をしていて関数名と関数を結び付けている。永続的なハッシュ構造なら忘れることはないのだが、人間の脳はニュートラルネットワークであるが故、あくまでもハッシュ関数を模倣しているだけなのである。
つまり、どうせ完全ではない自分の脳までもが関数に組み込まれているため、それがどれだけ自分にとって重要なライブラリであっても、関数名命名は適当な時間で行い切り上げることが重要であるのではないかという事を実感させられる。