Hatena::ブログ(Diary)

西尾泰和のはてなダイアリー

2010-07-30

抜粋翻訳 PEP 238: Changing the Division Operator

概要

現在の除算演算子 (/) は数値を引数として使った場合の意味が曖昧である。引数がintやlongの場合には、数学的な除算の結果を切り捨てたものを返す。しかし、引数がfloatやcomplexの場合には除算の結果の妥当な近似値を返す。

この異なる演算のために異なる演算子を導入することによってこの問題を修正することを提案する: x/yを数学的な除算の結果の妥当な近似値を返す除算(真の除算), x//yを切り捨てた値を返す除算(切り捨て除算)とする。現在の、意味の混ざった x/y を「従来の除算」と呼ぶ。

動機

従来の除算命令では任意の数値入力に対して正しい結果を返す数式を書くのが困難である。他の演算子全てに関しては x*y**2 + z などの式を書くことができ、どんな数値型(int, long, float, または complex)の入力であってもその計算結果は数学的な結果に近い(もちろん計算精度の範囲内で) しかし除算は問題を起こす。もし運悪く除算の両方の引数が整数型だったら、真の除算ではなく切り捨て除算になってしまう。

この問題は動的型付け言語に特有のものである: Cのような静的に片付けされた言語では、入力(多くの場合関数の引数)はdoubleやfloatであると宣言されているだろう。そして整数を引数に渡して呼び出した場合、呼び出し時にdoubleやfloatに変換される。

訳注

これは個人的には「なぜそんな変更をしたのか謎だ」と思っていた、1 / 2 == 0.5 への変更についてのPEPだ。何が問題だと考えてこの変更を行ったのか腑に落ちた。

しかし、OCamlみたいに「そもそも整数の演算と浮動小数点数の演算が別物なんだから全般的に演算子を分けるべきじゃないか」という意見や、Haskellみたいに「そもそも整数と浮動小数点数の演算を許しているのが問題なんじゃないのか」という意見、Schemeみたいに「いや1/10を0.1にした時点ですでに正しい計算じゃないだろ」という意見もあり、この解決方法が唯一の正解とはいえない。

数の構造をどうやって言語の中にモデル化するか、という難問なんだな。

しまった

今朝翻訳した PEP238ってすでに翻訳されてるじゃん

http://homepage3.nifty.com/text/script/python/pep-0238.ja.html

PEP Indexに載ってるのを見落としたのかと思ったけど載ってないな

http://sourceforge.jp/projects/pythonjp/wiki/PEPIndex

今後の翻訳予定は下のようになっているのだが、チェックしよう

概 SF  236  Back to the __future__                                  Peters
概 SF  227  Statically Nested Scopes                                Hylton
 SF  255  Simple Generators                                       Schemenauer, Peters, Hetland
概 SF  238  Changing the Division Operator                          Zadka, GvR
概 SF  328  Imports: Multi-Line and Absolute/Relative               Aahz
 SF  343  The "with" Statement                                    GvR, Coghlan
 SF 3105  Make print a function                                   Brandl
 SF 3112  Bytes literals in Python 3000                           Orendorff
http://docs.python.org/library/__future__.html

Simple Generatorsは翻訳済みだね。343は検索してみたけどとりあえず見当たらない。3105と3112もそうだけど、でもこれはあんまり面白くなさそうだなぁ。むしろ3141の方が面白そうだ。

[]今日覚えた

final blow とどめ, 最後の一撃

rant どなる、がなる、暴言

抜粋翻訳 PEP 343: The "with" Statement

概要

このPEPは、try/finally文の標準的な使い方を切り出すことが可能なように、Python言語に新しい文 "with" を追加する。

このPEPの中で、「コンテキストマネージャ」はメソッド __enter__() および __exit__() を提供する。これはwith文に入る際と出る際に呼ばれるメソッドである。

導入

PEP 340とその代替案に関するたくさんの議論を経て、私は PEP 340 を撤回することに決めた。そして若干の変更を加えたものを PEP 310 で提案した。さらなる議論の末、throw()メソッドを使って停止中のジェネレータの中で例外を投げることの出来る機能と、そして新しい例外 GeneratorExit を投げる close() メソッドをを追加し直した。これらの追加は当初 python-dev [2] で提案され、全面的に賛同されたものである。また、キーワードをwithに変更した。

動機と要約

PEP 340, 無名ブロック文, はいくつものパワフルなアイデアを結びつけた。ジェネレータをブロックのテンプレートとして使う、ジェネレータに例外ハンドリングと終了処理を追加する、などである。一部の称賛を横目にたくさんの反対意見が出された。彼らは元々あった、だがはっきりとは見えていなかった、潜在的なループ構造が気に入らなかったのだ。つまり、ブロック文の中でのbreakやcontinueはそのブロック文をbreakしたりcontinueしたりする。たとえそれがループをしないリソース管理ツールとして使われていたとしても。

しかし、とどめは私がRaymond Chenのフロー制御マクロについての暴言[1]を読んだときに刺された。Raymondは確信を持ってマクロのなかにフロー制御を隠してしまうのはコードを理解不能にすると主張した。そして私は、彼の主張がCと同様にPythonにも適用できる、と気づいた。PEP 340のテンプレートはあらゆる種類の制御フローを隠すことが出来る。たとえば、PEP 340の例4 (auto_retry()) は例外をキャッチしブロックを3回まで繰り返す。

この点、PEP 310のwith文は、私の見解では制御フローを隠さない。finally節は一時的に制御フローを停止するだろうが、最終的には、finally節がまったくなかったのと同じ形に戻る。

抜粋翻訳: Python Reference Manual: Lexical analysis

「Pythonで長くなった行を折り返すのって難しくないの?」

「全然難しくないよ。オフィシャルのコーディングスタイルガイドで79文字以下にすることが推奨されているくらいだし」

「その時のインデントってどうすればいいの」

「え?そんなの自由だよ」

「え?そうなの?」

というやりとりがあったので翻訳

2. Lexical analysis — Python v2.7 documentation

http://docs.python.org/reference/lexical_analysis.html

論理行

論理行の終わりはNEWLINEトークンで表現される。文は、構文規則でNEWLINEトークンが許されている場所以外で論理行の境界をまたぐことはできない。論理行は1行以上の物理行で構成される。その構成は後述の明示的行継続ルールと暗黙的行継続ルールに従う。

(明示的行継続ルールってのは行末にバックスラッシュを置くと行がつながるってルールのことだ。翻訳はしない)

暗黙的行継続

括弧、波括弧、大括弧で囲われた式はバックスラッシュなしで複数の物理行に分けることが出来る。例:

month_names = ['Januari', 'Februari', 'Maart',      # These are the
               'April',   'Mei',      'Juni',       # Dutch names
               'Juli',    'Augustus', 'September',  # for the months
               'Oktober', 'November', 'December']   # of the year

継続行はコメントを持てる。継続行のインデントは重要ではない。空白の継続行は許される。暗黙の継続行の間にNEWLINEトークンはない。暗黙の継続行は後述の「三重引用符で囲われた文字列」の中にもできるが、こちらはコメントを持てない。

インデント

続く行のインデントレベルはスタックを使ってINDENT及びDEDENTトークンを作るのに使われる。

最初の行が読まれる前に、一つの0がスタックにプッシュされる。この0はポップされない。スタックにプッシュされた値は常にスタックの底からてっぺんに向けて増加する。各々の論理行が始まるときに、その行のインデントレベルがスタックトップと比較される。もし同じ値ならなにもしない。もしその行のインデントレベルのほうが大きいなら、その値をプッシュし、INDENTトークンが作られる。もし小さいなら、インデントレベルはスタックの中にある数値のどれかでなくてはならず、スタックの中の値でインデントレベルよりも大きな値はすべてポップされ、そのポップごとに一つのDEDENTトークンが作られる。ファイルの最後で、残っている0より大きな値の数だけDEDENTトークンが作られる。


さて、もうおわかりかと思うが、例えばこんなインデントも許される。

>>> if True:
...     print (1 +
...   2)
... 
3

Python的にはprintの次の行はprintの行の続きなので、print (1 +  2)って書いてあるのと変わらない。

そういうわけで、普通の神経の持ち主が「見やすくするためにレイアウトしたい」と思うシチュエーションでPythonのルールがじゃまになることはないと言っていいだろう。少なくとも頭のおかしい人間が正方形プログラミングなんてやってしまう程度にはフリーレイアウトである。西尾泰和のブログ: ワンライナーはダークサイド。改行をいれるべし

PEPのススメ

講義資料の続き

PEPのススメ

さて、言語の設計の違いについて学ぶことは重要だが、不毛な議論で時間を浪費することは避けなければいけない。

ならばどうするのがいいだろうか?

正解はないが一つの案としてPEPを読むのはどうだろう?

PEPとは

Python Enhancement Proposals

http://www.python.org/dev/peps/

Pythonをこう改良したらいいんじゃない?という提案

採用されることもあれば却下されることもある

詳細はPEP 1で定義されているよ 和訳: http://sphinx-users.jp/articles/pep1.html

なかには本気かと思うような提案もある

PEP 3117:Postfix type declarations

Unicodeの絵文字で型宣言をつけよう」

def normpathƛ(path✎)✎:
    """Normalize path, eliminating double slashes, etc."""
    if path✎ == '':
        return '.'
    initial_slashes✓ = path✎.startswithƛ('/')✓

これはRejected(却下)されている。

(はてなじゃ表示できないのか)

PEP一覧の俯瞰

  • Meta-PEPs: PEP自体や手続きに関するPEP
  • Informational PEP: ガイドラインなど
  • Accepted PEPs: 受理されて未実装
  • Open PEPs: 議論中
  • Finished PEPs: 実装済み
  • Deferred, ... and Rejected PEPs: 却下など
  • 番号順一覧

Accepted PEPsとFinished PEPsの、それも互換性を失わせるような変更を重点的に読んでみよう。

なぜなら互換性を捨てるような提案が採用されているということは、

  • 互換性を捨ててまで採用するほど重要な問題で
  • 説得力がある=それがなぜ重要であるのかが明確に説明されている

ということだからだ。

_

  • ここにいくつかのPEPの概要などを入れてざっくり紹介する
  • いくつかピックアップして解説をする
    • True division、数値の型階層から他の言語の比較、IEEE754などなど現実の理想的なモデルをプログラミングできるものに落としこむことの困難さについて話す?
    • String Representationで、英語で発信することの重要さ、プログラマはプログラミングだけで世界を変えるのではなく、時には自然言語がとてもパワフルな道具になりうる、って話をする?

他の選択肢も挙げる

  • JSR
  • SFRI
  • EEP
  • RFC

_

ソースコードがドキュメントだ」という主張に対する反論

ソースコードには「いま現在どうなっているか」しか書かれていない。「過去になにがあっていまこうなっているのか」や「未来にはこういう実装に変わるべきである」は書かれていない。

PEPはPythonの過去や未来について書かれた文章だ。

2010-07-29

LISP

http://journal.mycom.co.jp/news/2010/07/27/007/index.html via @maeda

「LISP」は、「ひだまりスケッチ」シリーズのゆの役や『WORKING!!』の種島ぽぷら役などでおなじみの人気声優・阿澄佳奈を中心に、『おねがいマイメロディ』で夢野歌役を演じた片岡あづさ、現役女子大生声優として注目される原紗友里の3人が集結。"キミとセツゾク"をコンセプトに、かつてない"毎日ファンとコミュニケーションする声優ユニット"として活動する。

ラノベに進出したと思ったら次は声優ユニット化?! LISPはんぱねぇ!

しかしやっぱり「コミュニケーション」はうりなのね。REPLですか

抜粋翻訳 PEP3137: Immutable Bytes and Mutable Buffer

導入

Python 3.0a1で変更可能なバイト列型を公開して以来、変更不可能なバイト列型を表現する方法を追加せよとの圧力が強まった。

(中略)

古いPyStringの実装を使い、ロケールサポートとユニコードとの間の暗黙の型変換を取り除いて変更不可能なバイト列型とし、新しいPyBytesの実装を変更可能なバイト列型としてとっておく。

長所

変更不可能なバイト列型をもつことの一つの長所は、コードオブジェクトがそれを使うことができることだ。また、バイト列型をキーとするハッシュテーブルを効率的に作成できるようになる。これはHTTPやSMTPのような、バイト列に基づいてテキストを表現するプロトコルのパースに便利である。

バイナリデータ(やエンコードされたテキスト)を扱うPython2.x用のコードの移植は、この新しいデザインでの方が、元の変更可能なバイト列を用いる3.0でのデザインよりも楽である。単にstrをbytesに置き換え、'...'リテラルをb'...'リテラルに置き換えるだけである。

名前

下記のPythonレベルの型名を提案する

  • ``bytes`` は変更不可能なバイトの配列 (PyString)
  • ``bytearray`` は変更可能なバイトの配列 (PyBytes)
  • ``memoryview`` は別のオブジェクトのバイトビュー (PyMemory)

``buffer`` と呼ばれていた古い型はPEP 3118で導入された新しい型 ``memoryview`` に似すぎているので削除される。

要約

    +--------------+-------------+------------+--------------------------+
    | C name       | 2.x    repr | 3.0a1 repr | 3.0a2               repr |
    +--------------+-------------+------------+--------------------------+
    | PyUnicode    | unicode u'' | str     '' | str                   '' |
    | PyString     | str      '' | str8   s'' | bytes                b'' |
    | PyBytes      | N/A         | bytes  b'' | bytearray bytearray(b'') |
    | PyBuffer     | buffer      | buffer     | N/A                      |
    | PyMemoryView | N/A         | memoryview | memoryview         <...> |
    +--------------+-------------+------------+--------------------------+

抜粋翻訳 PEP227: Statically Nested Scopes

概要

このPEPは Python 2.2 への静的にネストしたスコープ(レキシカルスコープ)の追加と、Python 2.1へのソースレベルでのオプションについて記述する。また、 Python 2.1はこの機能がenableされた場合に意味が変わるような構造について警告をする。

従来の言語仕様(2.0以前)では、変数名を解決するのに用いる名前空間をちょうど3つ定義していた。ローカル、グローバル、そしてビルトインの名前空間である。ネストしたスコープの追加によって、未束縛のローカル変数名をそれを包む関数の名前空間で解決することが出来るようになる。

この変更によるもっとも分かりやすい結果は、無名関数(や他のネストした関数)が、それを取り囲む名前空間で定義された変数を参照できるようになることである。現在、無名関数では(訳注:外で定義された変数を)無名関数の名前空間に明示的に束縛するためにデフォルト引数を頻繁に使わなければいけない。

導入

この提案は、Pythonの関数の中の自由変数を解決する方法を変更する。新しい名前解決の動作は Python 2.2 から効果を発揮する。この動作は Python 2.1 でもモジュールに"from __future__ import nested_scopes"と付けることで利用可能である。(PEP 236を参照)

Python 2.0の仕様はそれぞれの名前を解決するのに、ちょうど3つの名前空間だけを定めていた。ローカル名前空間、グローバル名前空間、そしてビルトイン名前空間である。

この定義により、もしある関数Aが別の関数Bの中で定義されている場合、Bの中で束縛されている名前はAの中からは見ることができない。この提案はこのルールを変更し、Bの中で束縛された名前がAの中でも見えるようにしよう(ただしAがBの束縛を隠してしまうような名前束縛を含まない場合に限る)というものである。

この仕様はAlgol系の言語で普遍的なレキシカルスコープのルールを導入する。レキシカルスコープとすでにサポートされているファーストクラスの関数の組み合わせは、Schemeを連想させる。

変更されるスコープのルールには2つの問題があった。ラムダ式(と一般にネストした関数)の限られた機能、そしてネストしたレキシカルスコープをサポートしている他の言語に慣れた新規ユーザが頻繁に混乱すること、例えば再帰的な関数はモジュールレベルでしか定義できないことなど、である。

ラムダ式は一つの式だけを評価する名前のない関数を作る。これはよくコールバック関数として用いられる。下記の例(Python 2.0のルールを使って書かれている)では、ラムダの本体の中で使われている名前はすべて、明示的にラムダのデフォルト引数として渡さなければならない。

  from Tkinter import *
  root = Tk()
  Button(root, text="Click here",
         command=lambda root=root: root.test.configure(text="..."))

このアプローチはめんどくさい。特にいくつもの名前がラムダの中で使われる場合には。

デフォルト引数の長いリストはコードの目的を分かりにくくする。提案する方法では、ぶっきらぼうに言えば、デフォルト引数のアプローチを自動的に実装することでこの問題を解決する。この"root=root"という引数は削除できる。

新しい名前解決の動作は Python 2.0 と異なる振る舞いが原因でいくつかの問題を起こす。ある場合にはプログラムのコンパイルができなくなり、またある場合では以前はグローバルの名前空間で解決されていた名前が外側の関数のローカルの名前空間で解決されるようになる。Python 2.1では、異なる挙動をする文すべてについて警告が発せられる。

Rubyのスコープが面白かった件

$ irb
>> $o_o = o_o =-~ ( "o_o" =~ /o_o/ )
=> 1
>> def o_o (o_o) $o_o + o_o end
=> nil
>> o_o
=> 1
>> o_o o_o
=> 2
>> o_o o_o o_o
=> 3
>> o_o o_o o_o o_o
=> 4

個人的には関数と非関数で名前空間が分かれてるのか!と驚いたのだけど、でもまあメソッドとプロパティの名前空間が分かれてるって考えるとそれほど驚きでもないのかも知れない。むしろf f f が f (f f) と解釈されることも驚きなんだけど。

なお最初は $o_o = o_o = 1 と書いていて「この1が顔文字だけれ作れればなぁ」って言っていたら id:hzkr 氏に作ってもらえました。感謝♪

2010-07-28

講義資料の続き

Beating the Averages

プログラミング言語は半分技術で、半分は宗教なんだ [注6]

...

注6: 結果として、プログラミング言語の 比較は宗教戦争になるか、中立であろうとするあまりに 人類学の研究かと見まごうような学部生用の教科書にしかならない。 平和を好むか、大学での終身雇用を手に入れたい人は、この話題を避けて通る。 でも、宗教的な部分はこの問題の半分だけなんだ。他の部分には研究すべき価値がある。 特にあなたが新しい言語を設計したいと思っている時には。

というわけで、本当はもう少し宗教論争的な意味で炎上することを期待していたんだけどなー。真面目に書きすぎだと複数人に指摘された(苦笑)

炎上してから公開するつもりだった原稿の続き:


賢者は歴史から学ぶ。愚者は経験からしか学ばない。

自分で適当な設計で作って罠にはまる前に、既存の言語処理系を色々見比べて、どんな設計を採用したのか、どういう失敗をしたのかを学ぶことが重要だ。

しかし言語間比較は不毛な論争を招きやすい。

なぜか?


ある設計上の問題に対して解決策Aと解決策Bはどちらがよいのだろうか?

例えばGCはデフォルトでONがいいのか、それとも必要な人だけ使えるのがいいのか?

文字列は破壊的に変更できる方がいいのかできない方がいいのか?

整数や多倍長整数や浮動小数点数や文字列の間の暗黙の型変換はある方がいいのかない方がいいのか?

「選択肢Aが正解だ」

と言えると思っている?

それは視野が狭い。

現実社会の問題の大部分は簡単に割り切れない「ケースバイケース」な問題だ。

メモリの消費量や実行時間にシビアでないケースではGCまかせにしたほうがプログラマは楽かもしれない。

しかし組み込みでメモリがとても少ない場合や、例えばシューティングゲームみたいにゲーム中にGCが走るとユーザがイラッとする場合などGCまかせにしたくないケースはいくつもある。

唯一の正解があるはずだという思い込みは不毛な議論を招きやすい。


よく起こる不毛な議論のパターン:「宗教論争」「自転車置場の議論」

宗教論争とは

言語Xと言語Yのユーザがそれぞれ「自分の使っている言語の設計/機能が正しい」と考え、相手の言語の設計を「自分の信じる正しい言語と設計/機能が違う」という理由で互いに批判する状態。(一般的には言語の設計に限らずエディタやOS、政治、そして宗教も対象になる)

言語Xの信者が主張する「正しさ」が「言語Xに近いこと」なので、何が正しいのかについて意見がまとまるはずがない。不毛な議論である。


宗教論争はなぜ起こるか

全ての言語を均等に知っている人はいないので、どんな人の発言にも「彼の得意な言語がなんであるか」に起因する偏りがある。

人間には自分の慣れたものに愛着を感じる傾向があるので、自分の得意な言語をほめすぎることが多い。

また自分の知らないものの価値を認めることは難しい。よって自分の知らない言語のユーザが自分のよく知らないくだらない機能を高く評価し崇め奉っている「信者」にみえてしまう。

また、特に1つの言語に愛着が強い場合、その言語の欠点を指摘されるとたとえ的を射ていようが「自分に対する攻撃」と感じてしまい、防衛のための反論をしがち。


自転車置場の議論とは

駐輪場に屋根をつけるかどうか、何色に塗るか、といった些細な問題ほど議論に参加する人が多くなる現象。

プログラミング言語で言えばsleepの引数が秒であるべきかミリ秒であるべきか、文字列のリストを結合するのはString#joinであるべきかList#joinであるべきか、配列の各要素に関数を適用するメソッドの名前が map であるべきか collect であるべきか、などの議論。

こういう議論が無意味なわけではないが、大勢で考えなければいけないような問題でもないし、必死になって自分の主張を貫くような価値のある対象でもない。

自転車置き場の議論はなぜ起こるか

人間には「他者から関心・注目・反応が欲しい」という承認欲求がある。承認欲求に飢えている生き物にとって、大勢が参加する議論に加わるのはいいエサだし、万が一自分の意見が通りでもしようものならすごいご馳走だ。

だから簡単そうな問題にはまず素早い人が口を挟み、議論の参加者が増えたことで自分も一言噛んでおこうと思う人でますます議論が紛糾し、そして彼らは自分の名誉と注目を守るために必死に他の意見を貶めようと発言する。


ある種の自然現象

宗教論争も駐車場の議論も、人間がそういう性質の生き物だから起きる自然現象だ。自分が起こさないように努力をすることは必要だが、起きてしまったことに嘆いたり怒ったりしても無意味。夏が暑くて時々夕立になることと同じ。夕立をふらせた雲に文句を言っても雨はやまない。

夕立に怒るのでも夕立が降るのを嘆くのでもなく、夕立の時には雨宿りをして、濡れて風邪をひかないようにするのが賢明。


「PEPのススメ」に続く。

抜粋翻訳 PEP3138 String representation in Python 3000

PEP3138 String representation in Python 3000

概要

この文章では、Python 3000用に文字列の新しい表現方法を提案する。 Python 3000以前のPythonでは、組み込み関数repr()はデバッグやログ出力のために、任意のオブジェクトを画面表示可能なASCIIの文字列に変換していた。 Python 3000ではユニコード標準に基づいて、より広い範囲の文字を「画面表示可能」とみなすべきである。

動機

Python2.*系では「表示可能な文字列を作成する関数」reprは、非ASCII文字をすべてエスケープする。文字列を構成する文字のほとんどがASCIIである場合には問題にならない。しかし、日本語などいくつかの言語ではほとんどの文字が非ASCIIであり、とても不便である。

例えば open(japaneseFilemame) が何か例外を投げる場合、エラーメッセージは IOError: [Errno 2] No such file or directory: '\u65e5\u672c\u8a9e' といったものになる。

Python 3000 には、非ASCII識別子など、ラテン文字以外を使用しているユーザーに優しい特徴がたくさん盛り込まれている。表示可能な文字列の作成に関しても同様に進化できればきっと役に立つことだろう。

抜粋翻訳 PEP 236 Back to the __future__

PEP 236 Back to the __future__

動機

時が立つにつれて、Pythonは言語コアの構造の広く知られた意味づけに互換性のない変更を加えたり、思いがけない(実装依存の)振る舞いを何らかの形で変更したりする。こういう変更は気まぐれには行われず、常に長期的に見て言語を改善する目的で行われるのだが、しかし短期的には論争と混乱を呼ぶものである。

PEP 5, Guidelines for Language Evolution[1] は痛みを減らす方法を提案している。このPEPでは、それを実現するためのメカニズムを導入する。

意図

言語コア部分の構文や意味論に互換性のない変更を加える際は:

1. その変更が導入されるリリースCでは構文や意味論をデフォルトでは変更しない。

2. ある将来のリリースRを、そこでその構文や意味論が強制されるものとする。

3. PEP 3, Warning Framework[3] で説明されているメカニズムが、リリースRで意味を変えるであろう操作や構成について、可能な限りいつでも、警告を作成するのに使われる。

4. モジュールMの中のコードが現在のリリースCで新しい構文や意味論を使うことを要求するために、新しい future_statement (後述) を明示的にモジュールMに含めることが出来る。

つまり、古いコードは少なくとも一つのリリースでデフォルトで動き続け、しかし新しい警告メッセージを表示しはじめるようになる。新しい構文や意味論への移行はこの期間中に進めることができ、future_statementを使って、それを含むモジュールがすでに新しい構文と意味論が強制されたあとであるかのように振舞うようにできる。

抜粋翻訳 PEP 3107 Function Annotations

概要

このPEPはPythonの関数に、任意のメタデータを追加するための構文を導入する。

根拠

Python 2.x 系は関数の引数と返り値を修飾する方法を持たなかったため、数多くのツールやライブラリがそのギャップを埋めるために現れた。いくつかは PEP 318 で導入されたデコレータを使い、他のいくつかは関数のドキュメンテーション文字列をパースしてアノテーションを探す。

このPEPは、このような情報を指定する、唯一の標準的な方法を提供し、今現在幅広い方法と構文のバリエーションが引き起こしている混乱を軽減することを目指している。

関数アノテーションの前提

  • 関数アノテーションは、パラメータと戻り値の両方とも、完全に任意。
  • 関数アノテーションはコンパイル時に任意のPythonの式を関数のさまざまな部分に関連付ける方法以上のなにものでもない。Pythonそれ自体はアノテーションに特定の意味をもたせることはしない。
def compile(source: "something compilable",
            filename: "where the compilable thing comes from",
            mode: "is this a single statement or a suite?"):
    ...
def haul(item: Haulable, *vargs: PackAnimal) -> Distance:
    ...

2010-07-26

レバレッジメモ: プログラミング言語の概念と構造

プログラミング言語の概念と構造。例の原稿を書く前にid:yuguiさんから借りたのに結局読みもせずに自分の記憶と勢いで原稿を書いてしまったのだが、今更読んでみた。っていうかこれはかなりいい本だ。というわけで返す前にレバレッジメモ作成。

参考文献のリストの引き写しは今日はもう遅くて眠いのでまた今度。


マリナーI無人金星探査機は1962年7月22日発射から290秒後に爆破された。損失は1800から2000万ドルと見積もられる。notの欠落が原因である。

1950年代には効率のよいプログラムは人がマシン語を書くことでのみ作られると信じられていた。この信念にFortranが挑戦した。

最初はアセンブリ言語で書かれていたUNIXカーネルは1973年にプログラミング言語Cによって書き換えられた。利点は「新しいユーザとプログラム」「移植性」「可読性」 Ritchie[1978] *1

BNFのNaurはAlgol60の報告書にBNF(当時はBackus Normal Form)を使った

初期のFortranではIからNで始まる変数はint型、それ以外はreal型であり、異なる型の加減乗除は出来なかった。後にrealとintの計算の際にはintがrealへと強制型変換されるようになった。

60年代の言語設計はAlgol60をどう改善するかに終始した。構文を指定するのにBNFを使うのもAlgolからの伝統。しかしAlgolにはデータ構造として配列しかなかった。

「Algol60のコードをPascalに変換することは単純な転記と考えて差し支えない」 Wirth[1971] *2

Modula-2は「Pascalのすべての側面を含んだ上で、重要なモジュール概念を持つように拡張した。」「あらゆる構造がキーワードで始まりキーワードで終わるようにした」

「Cが提供する機能に加えて、C++は新しい型を定義する柔軟で効率的な機能を提供する」Stroustrp[1986] *3 新しい型はSimula67から借用したクラスを用いて定義される。

今日のCと1972年のCの主な相違点は型検査に対する今日の厳格な態度である。現在ではある型へのポインターが整数や他の型へのポインターを装うことができなくなった。

代入演算子: Cでは式の中に代入を書くことが出来る(Pascalではダメ)

Knuth[1974]*4はgotoの有害性を最初に発表したのがNaur[1963a]で、Dijkstra[1968a]が流行らせたとしている。

Lispではダイナミックスコープが伝統的に使用された。最近のLispではレキシカルスコープを採用する傾向がある。 --- 太古の極初期のLisp(とEmacsLisp)くらいかとおもったら「伝統的」だったのか。ダイナミックスコープが終わって僕らは生まれた、ダイナミックスコープを知らない子供たちさ〜♪

値呼び出し: 右辺値を渡す、参照呼び出し: 左辺値を渡す、名前呼び出し: 名前の衝突を避けつつテキストそのものを渡す --- この簡潔なまとめは目からウロコ

初期のFortranでは実参照パラメータが代入可能かどうかを検査しなかった。その結果、swap(1, 2)は定数の1と2を交換してしまうことがあった。言語によっては左辺値を持たない式が実引数に指定された場合には値呼び出しを用いることでこの問題を避ける。

Cのマクロプリプロセッサは「名前の衝突」を無視した名前呼び出し。Algol60の名前呼び出しは衝突する際に局所名を変更するので大丈夫。

モジュールはプログラムを適度なサイズに分割したものであり、公開されている部分と、公開されていない内部状態とがある。

真の抽象仕様は実現が困難。実装隠蔽、カプセル化、表現独立によって、非公開部は外部に影響を与えることなく変更できる。

Modula-2のモジュール=可視性+初期化 明示的なimport/exportなしにモジュールの境界を超えてアクセス出来ない。

不透明な輸出(opaque export)とは型の名前だけのexport(構成要素を見せないの意)。代入と等価性のチェック、および明示的にexportされた他の操作だけしか使用できない。 --- HaskellのIOモナドの内部にアクセス出来ないのもこれだよね。

C++の基本型/派生型は上位型/部分型(サブタイプ)より一般化されている。private継承をすれば導出クラスが部分型となることを防ぐことが出来る。

List ProcessorであるLispはFortranのFLPL(Fortran List Processing Language)という拡張に萌芽がある。FLPLには再帰がなく、式の中に条件を書く事もできなかった。

プログラミング言語に置ける並行性とハードウェアにおける並列性は互いに独立した概念である。ハードウェアの演算はそれが時間的に重なりあって行われるときに並列(parallel)であるという。ソーステキスト上の操作は、並列に実行されることが可能であれば並行(concurrent)であると言われるが、必ずしも並列に実行される必要はない。 --- 今まで聞いた中で一番わかり易いparallelとconcurrentの違いの説明だ!

BNFに類似の表記法がサンスクリット語の複雑な文法を記述するために紀元前400年〜200年頃、古代インドの言語学者Paniniによって使用されていた Ingerman[1967]

*1:Dennis M. Ritchie The Evolution of the Unix Time-sharing System http://cm.bell-labs.com/cm/cs/who/dmr/hist.html

*2:The Programming Language Pascal. Acta Informatica, 1, (Jun 1971) 35-63. also in Programming Language Design, A.I.Wasserman, Ed., IEEE Computer Society Press, 1980.

*3:The C++ Programming Language Addison-Wesley, ISBN 0-201-88954-4 and 0-201-70073-5.

*4:Structured programming with go to statements (1974) http://pplab.snu.ac.kr/courses/adv_pl05/papers/p261-knuth.pdf

2010-07-25

[]洗濯物を干した

最近書いてないなと言われたので。

洗濯物を干した。前回の洗濯物を取り入れた際に、たたんでかごに直していたので、下着干しやハンガーに十分余裕がある。すぐに干せる。洗濯を開始した時点で余裕が無いなら事前に実行しておくと洗濯が終わったあとで干すタスクにとりかかる際のイニシャルコストが削減できる。

いままで洗濯物を干す際には、洗濯機の中で絡まった洗濯物をかごに入れて、1個とってハンガーor下着干しに装着して、また1個とる、というタスクを実行していた。これは事前に1工程増やして「下着とシャツを分離する」をしたほうがよい。一度ばらしていることで絡まったシャツなどの「予期しないインタラプト」が入らないし、下着干しとハンガーの間でのコンテキストスイッチがなくなって全体としてのパフォーマンスも上がる。

[]麦茶のダブルバッファ

最近、前から持っていたのに使っていなかった2リットルの麦茶を作る冷蔵庫に入れる容器の利用を開始した。片方のお茶がなくなると、即座に古いお茶パックを捨てて水を入れて冷蔵庫にしまう。そうするともう片方のお茶を飲み終わる頃には新しいお茶ができている。いつでも飲み物がある。

2010-07-24

Haskellの「fib = 1:1:zipWith (+) fib (tail fib)」がとても遅い件のまとめ

前日話の流れを時系列でまとめかけたけど、もはや情報量が多すぎて流れを追っていなかった人にとってはキャッチアップが困難かと思うので改めてまとめてみる。(情報量の多いほうがいい人はこちら: 続:Haskellのfibが遅い件)


Haskellでフィボナッチ数列を定義する方法としては

fib = 1:1:zipWith (+) fib (tail fib)

が有名であり、Wikipediaには「次の定義は線形時間でフィボナッチ数列のリストを生成する」と紹介されている。しかし、少なくとも n = 10000 〜 300000 くらいの範囲ではO(n^2.6)くらいの計算時間が掛かっていて、事実に反する。 (グラフはこちら: はじめてのにき(2010-07-19))


2.6という値がどこから出てきたのか?これはGCにO(n^3)くらいの時間がかかっていて、それが小さい係数で本来の計算時間O(n^2)に混ざっているため、O(n^2.6)ぐらいに見えている。


なぜGCにO(n^3)ぐらいの時間がかかるのか?HaskellのGCは世代別GCであり、固定長のマイナーヒープがいっぱいになるとGCを始める。このとき、スタック上のオブジェクトはGCのルートとして使われるのでスタックの深さをmとしたときにO(m)の時間がかかる。今回のケースでは、スタックの深さをmとした場合にO(m)のメモリを確保するので、i回目のGCが起きたときの消費時間mは係数無視してi^0.5になり、これをiについて足しあわせるので積分してi^1.5になり、iがいくらまで増えるかというとメモリの消費量をマイナーヒープのサイズで割ったものだから係数無視してn^2なので、これを代入してn^3になる。というわけでGCの計算量はO(n^3)になる。


この挙動はGHC 6.10.1以前では再現しないので、6.10.2で行われたGCに関する修正(#2747 (Excessive Memory Usage: space leak with foldl' on Integer) – GHC)が原因と思われる。6.10.1ではnの2乗くらいのオーダーになるらしい。


また、「スタックの上に大量の巨大なIntegerがある状況」が問題を引き起こしているので、Haskellでも素朴に末尾再帰で書けばO(n^2)になる。計算順序によっても挙動が変わる(無限リストを使っているfibでは30万番目を取るより30万番目までの和を取るほうが速い)し、評価戦略でも変わる(正格評価するzipWith'を作れば速い)


無限リストが絡むことで見かけが複雑になっているので、よりシンプルな「末尾再帰でない再帰呼び出しでnに比例して大きくなるメモリを確保しようとしたときにO(n ^ 2.6)の時間がかかる」事例(Haskellで単にn回7を掛けるだけでもO(n ^ 2.6)の時間がかかる)を先に見たほうが分かりやすいのかも知れない


「Haskellが遅い」という主張にエアリーディングした人もいたようだが、あくまで「fib = 1:1:zipWith (+) fib (tail fib)が遅い(n = 100000ではPythonで素朴にループで書いたコードよりも!)」ということなので勘違いなさらないよう。実際最初のエントリーでも素朴な末尾再帰で書いて速くなってるわけだし。



こんな感じですかね。なんか間違っていたらご指摘よろしくお願いします。

今回の件で個人的に学んだことのまとめ

gnuplotの使い方

  • fit a*(x**b) "data.txt" via a, b
  • plot a*(x**b) "data.txt"
  • using (log ($1)):(log ($2))
  • set log x
  • unset log x

GC

  • GCは想像以上にいろいろな処理のオーダーに影響を与える

事実と解釈

他人と解釈が食い違う場合、特に自分がある事実Xを見て解釈している場合に、相手は事実を見ていないんじゃないか、と思い込みがちだが、別の事実Yを見ている可能性もある。非生産的な議論を避けるためには速やかに事実を共有する必要がある。

原稿をブログで書くメソッド

もうちょっと早く着手すべきだったなー。締切りを知った時点で締め切りが一週間後という。

公平性を重んじて偏りがないように慎重に書くよりも、炎上しそうなことを勢いで書いてしまって反論を受けて修正する方がスピードは速いわけだが、うむむ。

不完全にしてかなり言葉足らずな比較プログラミング言語

プログラミング言語は人が作ったもの。人は誤るもの。なので完璧なプログラミング言語は存在しない。

「人は誤るもの、しかし誤りに固執するのは馬鹿の所業だ。」(キケロ) プログラミング言語も、間違った設計をして、馬鹿でない人がそれを修正することの繰り返しで発展してきた。

というわけで言語間での設計判断の食い違いとか失敗した設計とかを収集中。一部抜粋して講義資料に入れるつもりなので他の事例をご存知でしたらぜひ情報をいただけるとありがたいです。

if(x = 0)

C言語では代入が式であるためif(x == 0)のつもりでif(x = 0)と書いてしまい、常に偽になってしまう。

  • x = 0の値はint、条件式はboolでないといけないので型エラーだよ派: Java
  • x = 0は式ではないので条件式に入れたら構文エラーだよ派: Python
  • 条件式にx = 0をいれたらx == 0と解釈するよ派: HMMMML *1

値渡し、参照渡し

C言語では関数を呼ぶ場合の引数の渡し方に、値渡ししかできなかった。変数のアドレスを取得し、それを値渡しし、呼び出し先でそのアドレスに間接アクセスすることで参照渡し風のことをすることができた。C++では呼び出し先で間接アクセスしないでいい参照渡しが導入された。

Javaでは「変数のアドレスを取得する方法」を取り除いた。オブジェクトへのアクセスはC++の参照のような見かけで、しかし関数に渡す際にはアドレスの値渡しで行う(参照の値渡し)とした。それで十分であった。非オブジェクト(プリミティブ型)は従来通り値渡しにした。

Pythonでは全てがオブジェクトのため、全てが参照の値渡しになった。整数や文字列などのプリミティブなものは変更不可能なオブジェクトにすることで「呼び出し先で破壊的変更を行うこと」を不可能にした。これによって参照が値渡しされていてもただの値渡しと同様になった。

値の範囲の定義

C言語では環境によって「intが何ビットであるか」などがまちまちのためプログラマに無駄な労力をさかせていた。Javaでは言語仕様としてintなどのプリミティブ型の大きさと値の範囲が定められている。

配列

Cの配列は長さを持たない。ただの「たまたま同じ型のデータが並んでいるメモリ領域の先頭へのポインタ」である。範囲外アクセスによる脆弱性の例は枚挙にいとまがない。Javaの配列は作成時点で長さが定められ、範囲外へのアクセスは例外を投げる。

Javaの配列はファーストクラスのオブジェクトであり、関数の引数にそれ単体で渡すことができる。

関数へのポインタ

Cは関数へのポインタを作成することが出来る。ポインタはファーストクラスのオブジェクトなので関数の引数に関数を渡すことが出来る。

Javaではそもそも関数がない。リフレクションによってメソッドオブジェクトを取得することは出来る。

C++では関数の呼び出しオペレータを定義したクラスを作ることが出来る。

LispHaskellやPythonの関数はファーストクラスのオブジェクトであり、なんら気兼ねなく関数の引数に渡すことが出来る。

Pythonでも関数の呼び出しオペレータを定義したクラスを作ることが出来る。

関数呼び出しの括弧

関数(メソッド)の呼び出しに

  • たとえ引数がなくても括弧が必要派: Python
  • たとえ引数がなくても括弧が必要、ただし外側にな、派: Lisp
  • 引数がないときだけ括弧を省略できるよ派: D (thanks id:Dubhead)
  • 括弧はいらないよ派: Perl, Ruby
  • 括弧はいらないよ、引数が0個の関数?なにそれ定数じゃん派: Haskell
  • 括弧はいらないよ、引数が0個の関数?引数に()を渡せ派: OCaml
  • 関数はおろか演算子の結合順序を変える括弧もいらないよ、(1 + 2) * 3 は 1 2 + 3 * って書けよ派: Postscript, Forth
  • 演算子の結合順序?計算は左からって決めればいいじゃん 1 + 2 * 3でいいよ派: Smalltalk
  • 演算は右から順だよ派: APL, J (thanks: straggler)

引数のない関数呼び出しに括弧がいらない、かつ関数がファーストクラスの言語では、逆に「その関数自体」を意味する式をつくるために新しい文法が必要になる。

たとえばPythonでこう書けるところを:

>>> def foo():
...     print "foo!"
... 
>>> bar = foo
>>> bar()
foo!

Rubyではこう書く事になる

>> def foo
>>   p "foo!"
>> end
=> nil
>> bar = Object.method(:foo)
=> #<Method: Class(Object)#foo>
>> bar.call
"foo!"
=> nil

演算子オーバーロード

C++では演算子の多重定義が可能である。たとえば「+」が再定義できる。これは乱用するととても読みにくいコードになる。

Javaでは演算子の多重定義を許さないようにした。結果、独自定義のクラスについてx + yと書きたくてもx.add(y)と書かざるを得なくなり、プログラムの可読性を損ねる結果となった。

PythonやRubyなどでは再び演算子の多重定義を許している。乱用するなよ、みんな大人でしょ、というスタンスである。

多重継承

C++は任意のクラスを多重継承できる。これはたまたま同じシグニチャのメソッド実装が複数あった場合にどの実装が選ばれるのか、という問題を引き起こす。*2

Javaは実装を持ったクラスの継承は1つまでとすることでこの問題を回避した。実装を持たないクラス(インターフェイス)はいくつでも継承できる。しかしこれは「複数のクラスから実装を引き継げない」という不便さと引換である。Javaではこういうシチュエーションで、もっぱら実装のあるクラスFooへの参照を持っておいて自分のbarメソッドが呼ばれたらFooのbarメソッドを呼んでそっちに処理を任せるという書き方をする。

Rubyは実装の継承を部分的に許すためにMix-inという概念を導入した。「インスタンスを作れず、クラスから継承もできない特殊なクラス」である「モジュール」をクラスに「混ぜ込む」構文を用意した。

Pythonは多重継承をサポートして、メソッドの解決順序の決定にC3-Linearizationっていう比較的自然な結果が得られやすいアルゴリズムを採用して、「まあ、多重継承を乱用すると悲惨なことが起こるってみんな知ってるでしょ、大人でしょ、これで普通は問題起きないでしょ」というスタンスである。*3

PerlはPythonと同じC3を併用可能だった。Perl 6からはデフォルトがC3になっている。 *4

GC

  • GC必要でしょ、メモリのこと気にするのとかめんどくさいでしょ派: Lisp, Java, Python, Ruby, その他最近の言語のほとんど
  • GCみたいなゆとりのための機能を入れて遅くなるとかありえん派: C
  • GCみたいなゆとりのための機能を入れて遅くなるとかありえん、スマートポインタでだいたい用が済むだろ派: C++
  • AutoreleasePoolでだいたい用は済むだろ、だけどやっぱりGCあった方が楽だよね派: Objective-C (thanks id:jmuk)
  • 普通はGCを使うけど必要ならmalloc/freeもできるよ派: D (thanks id:Dubhead)
  • リージョン推論(region inference)試してみたけれど、リージョン推論だけでは速度が出なかった。なので GC も使う派: Haskell (thanks id:shelarcy)

変数の初期化

  • 初期化が必要なら必要なときにプログラマがやればいい。デフォルトでやるなどというゆとりのための機能で遅くなるとかありえん派: C, C++
  • 初期化されていない(値がなんだかわからない)変数の存在は危険なバグのもとであり許してはいけない、勝手に初期化しよう派: Java, D (thanks id:Dubhead)
  • っていうか値を代入することでしか変数を作れないので未初期化の変数とかありえないし派: Python
  • 未定義の変数に謎の値が入ってるのがダメなんだよ、「未定義」って値を入れとけばいいじゃん派: JS

グローバル変数

C言語はグローバル変数を定義できる。グローバル変数の乱用に起因する問題はプログラマの責任である。

Javaではグローバル変数を定義できない。もしどこからでもアクセス可能なグローバル変数的なものが必要であれば、クラス名がどこからでもアクセス可能なことを利用する、というトリックがやはり場合により乱用されて問題を起こしたり。

Pythonではグローバル変数を定義できるように見えるが、それはファイル単位のスコープである。グローバル変数を書き換えるには特別の「この関数はグローバル変数fooを書き換えるぞ」宣言が必要である。本当にどのファイルからでも参照できる変数が欲しければ__builtins__モジュールに動的に追加する。

整除の丸め方向

C, C++では整数の除算が割り切れなかった場合に0方向に丸めるのかマイナス無限大方向に丸めるのかが環境依存である。つまり、-1/2は0にも-1にもなりえる。

Javaでは常に0方向に丸める。C99も同様。

Haskellでは整数同士を「/」で除算することはできない。divとquotという二つの整除関数がありdivが-1, quotが0を返す。

x / 0.0

x / 0.0 をエラーにすべきか否か

Ruby1.8ではNaNやInfinityにする。

Pythonでは例外を投げる。

0xxx型の8進法リテラル

>>> 1000 + 0100 + 0010 + 0001
1073
  • 0100は64だよ派: Python2.*, Java, Scala
  • 0o100と0O100は64だよ派: Python3.0, Haskell

Haskellの仕様を見て大文字のOを許容するとかダメだろ、と思ったらPython3.0でも同じだった

long intのリテラルに小文字のエルを許す

大文字Oで思いついたので:

>>> 100l == 100
True

整数演算の結果がintの範囲を超えたときに自動的に表現力の大きい型に変更する

Cで書かれたビット演算のコードとかを丸写しすると、「<<」で上位ビットが捨てられているようなところで長整数型に変わってしまって結果が合わないという罠。

しかし数値をビットの塊として認識していない人にとっては「人間の都合で上限が定められていて、それを超えても例外を投げるでもなく変な値になるってのはおかしい」という主張もまあ一理ある。

  • 上限のない整数になるべきだ派: Python、Ruby
  • 勝手に変換するのはよくない派: C, Java
  • ていうか整数なんてないし派: JS
  • そもそも上限のない方がデフォルトだし派: Haskell

変数への再代入を許すかどうか

  • え、当然許すよ何言ってんの派: Python
  • 定数はあったほうがいいよね。大文字で始まるのは定数。まあ再代入しても警告しか出さないけど派: Ruby
  • 再代入させたくないものだけconstとかfinalとかつけたらいいじゃん派: C++, Java
  • 変数への再代入なんて諸悪の根源だ派:
    • だから一切認めないッッ派: Haskell
    • でも完全に禁止すると実用的じゃないから書き込める場所を用意しましたor用意する方法を作りました派: Erlang, OCaml

演算子の優先順位について

Pascalでは加算演算子(+, -, orなど)は乗算演算子(*, /, andなど)より優先順位が低く、比較演算子(==, >など)はさらに低い。つまり 「4 + 1 * 2 == 3 * 2」は「(4 + (1 * 2)) == (3 * 2)」と解釈される。これは自然。しかし「0 < x and x < 9」は「0 < (x and x) < 9」になってコンパイルエラー

他の多くの言語では条件演算子(and, or)が算術演算子(*, /, +, -など)より低い優先順位になっている。

C では x == y & z が (x == y) & z となる(thanks @mametter)

比較演算子の連続について

  • 0 < x && x <= 9とか頻出パターンだし複数の比較の連続で一つの式って構文にしようよ。 0 < x <= 9 って書けるよ派: Python

単項演算子のマイナス

Haskellでは「f -1」が「f - 1」と解釈されるので「f (-1)」と書かなければいけない。逆に演算子の部分適用で(/ 2)は「2で割る関数」になるが(- 1)は-1と解釈される。

SMLでは ~1、J言語では _1。

ループ

  • ループをするにはforとかwhileとかgotoとかいろいろな方法があるよ派: C
  • gotoは悪だ、forとwhileだけでいいだろ派: Java
  • 末尾再帰がジャンプに置き換えられるから再帰呼び出しでループするのもありだよ派: Lisp
  • むしろループいらないよねmapとfoldlあるし派: Haskell

空リストの型

Cambridge LCF の MLではかつてlet x = ref [] で polymorphic な \forall a. a list ref が作れた

xにintの値を入れてからポインタとして取り出してアクセスすることができてしまう。

SML '97 Types and Type Checking http://www.smlnj.org/doc/Conversion/types.html

thanks id:camlspotter

インデントと実際の構造の不一致

C言語では下のようにif文を書くことができる。

if (x > 0)
  when_x_is_positive();

x > 0の時に別の処理を追加しようと考えてこんな書き方をしてはいけない

if (x > 0)
  when_x_is_positive();
  another_task();

これは下のような意味であり、another_task()は常に実行される。

if (x > 0) {
  when_x_is_positive();
}
another_task();

また下のコードにもインデントと構造の不一致がある。

if (x > 0) 
    if (y > 0)
	all_positive();
else 
    x_isnt_positive();

x == -1の時にx_isnt_positive()は呼ばれない。代わりにx == 1, y == -1の時に呼ばれる。このコードは下のような構造である。

if (x > 0) {
    if (y > 0) {
	all_positive();
    } else {
        x_isnt_positive();
    }
}

Cではプログラマが気をつけるか、braces {}を付けろ&正しくインデントしろというコーディング規約で回避する。

Rubyではendで閉じる。

Pythonでは発想を逆転してインデントをもとに構造を決める。下記のコードは見ためどおりに動く。

if x > 0:
    if y > 0:
	all_positive()
else:
    x_isnt_positive()

QuickBASICやHMMMML*5では他の言語における「end」や「}」でのブロック終了がどのブロックの終了であるのか分かりにくい点を改善するため「If ~ End If」(QB)「</if>」(HMMMML)などを用いる。

レシーバの受け取り方

obj.method(arg)的なコードを実行したときにmethodの中ではどうやってobjにアクセスするのかと言う話

  • レシーバは明示的に仮引数として受け取る派: Python, C (thanks @mametter)
  • メソッド内でanother_method()がobj.another_method()を意味しているのでレシーバを意識する必要はないけどレシーバ自体をどうこうしたい時にはthisに入っているよ派: Java
  • レシーバ?それ単なる引数だろ、特別なものじゃないじゃん派: Common Lisp with CLOS, Haskell

文字列オブジェクトは破壊的に変更できるか?

  • はい: Ruby, C++
  • いいえ: Python, Java
  • 文字列?なにそれ?char*のこと?: C

文字列と数値を自動変換するか?

PHPの場合

$ php -r 'print "1" + "2";'
3
$ php -r 'print "1" . "2";'
12
$ php -r 'print "1" . 2;'
12
$ php -r 'print "1" + 2;'
3

Perlも同じ

  • 文字列と数値は自動的に変換するよ、だから文字列の結合と数値の足し算は別の演算子だよ派: Perl, PHP
  • それは型エラーにするよ派: Python, Ruby
  • 数値に限らずオブジェクトは自分の文字列化の方法を知っているはず(toString)だから文字列への変換はしてもいいんじゃない?派: Java

1/2は何になる?

  • 整数の0だよ派: Python2.*, Ruby, OCaml
  • 浮動小数点数の0.5だよ派: Python3.*
  • 有理数の1/2だよ派: Scheme
  • 念のために確認するとその1や2ってのは Int じゃなくて (Num a) => a だよな?だったら計算結果は(Fractional a) => a だな。これは浮動小数点数と有理数のどちらでもありうる型クラスで、どちらになるかは型推論で決まる。ちなみに推論によって決定できないときにはDefaultingと(省略されました。続きを読むにはこちら): Haskell
  • 数値はデフォルトでBigDecimalだよ派: Groovy

オブジェクト指向

  • データと手続きを分けて管理するのは面倒だから、ひとまとめにしたオブジェクトとかクラスとかあると幸せになるんじゃない?: Simula
  • すべてはオブジェクトとその間のメッセージのやりとりで表現できるんだよ!メッセージ!メッセージ!: Smalltalk
  • なにそれ遅い…: C
  • ふむ、Simulaのクラスって概念はいいものだ。採用!要するにstructで既存の型を組み合わせて新しい型を作ってたのの延長で、そこに関数も組み合わせてひとかたまりにできればいいわけだよね。あ、あと継承ね。これも便利。採用!アクセス制限?ふむ、これもいれとくか。メッセージ?…なにそれおいしいの?: C++
  • プログラミングとはクラスを定義してオブジェクトを作ることなんだよ!オブジェクト!オブジェクト!え?プリミティブ型はオブジェクトじゃないじゃんって?えっと、まあ、それはそのパフォーマンスのためとかさ(ごにょごにょ): Java
  • じゃじゃーん、整数とかもオブジェクトにしたよ!プリミティブ型も自動でオブジェクトに変換するよ!オブジェクト!オブジェクト!: Java 5
  • っていうか要するにデータを持っておくハッシュと、関数の入っているモジュールを貼り合わせる手段があればいいだけだよね: Perl
  • そもそも関数がファーストクラスのオブジェクトならハッシュにだって入るじゃん。これでいいんじゃない?: JavaScript
  • そもそも名前空間自体が辞書(ハッシュ)だよね。手軽に名前空間を作れて関数を入れられて、ついでに継承とかメソッドとインスタンスのバインディングとか便利な機能がついてくる!これでよし!: Python
  • privateとかいらないよねー派: Perl, JavaScript, Python
  • 世間のスクリプト言語がprivateを軽視しすぎ!許せん!派: Ruby

真偽値

  • 真と偽の値はこちらが用意する。それ以外を条件式に入れたら型エラーだぞ派: Java, Haskell
  • 0がfalse、それ以外は真だよ派: C
  • #fが偽、それ以外は(0も)真だよ派: Scheme
  • falseとnilが偽、それ以外は(0も)真だよ派: Ruby
  • falseとnullとundefinedと0と空文字列とNaNが偽だよ: JavaScript
  • FalseとNoneと0なオブジェクトと空のオブジェクトが偽だよ: Python *6

スコープ

  • 静的スコープだよ、だって動的スコープとか大変じゃん派: ALGOL, C, Pascal
  • 動的スコープだよ派: 初期のLisp, 初期のPerl
  • 動的スコープと静的スコープ両方あるといいよね派: CommonLisp, Perl(my/local)
  • Lispが動的スコープいれたのって失敗じゃない?派: Scheme, Python
  • スコープ?なにそれおいしいの?: BASIC

配列の範囲外アクセス

  • 何か適当なものを返す: Ruby(nil), JavaScript(undefined)
  • 例外を投げる: Python, Java
  • 死ぬかも知れない: C

2010-07-23

レバレッジメモ: レガシーコード改善ガイド

レガシーコード := テストがないコード

テストを作成するためには対象とするクラスから他のクラスへの影響を把握する必要がある。依存関係を排除しておけばニセのクラスを突っ込んで影響を直接観察できる。

テストをするたびに本番コードを編集するわけには行かない、なのでコードを編集せずにテストに不都合な挙動を変えられる場所が必要である。これをseamという。どのseamも、その挙動を変更するenabling pointを持っている。

日本語で「接合部」っていうとくっつけることに意識が向きがちだけど「そこで切り離せる」というほうが重要なのだな。

既存のレガシーコードに機能追加をする方法

1: スプラウトメソッド

テストされてない既存のコードに書き足すのではなく、新しいメソッドを作ってそれを呼び出すようにし、その新しいメソッドにテストを書く

2: ラップメソッド

テストされていない既存のメソッドの前か後ろに処理を付け足す場合、テストされていないメソッドの名前を変えて、元の名前で古いメソッドと新しく追加する機能の入ったメソッドを呼び出すようにし、その新しいメソッドをテストする。

TDD

  • 1: 失敗するテストを書く
  • 2: コンパイルが通るようにする
  • 3: テストを通過させる。この時既存のコードをなるべく変更しない。「これはFooメソッドとほとんど同じで一部だけ違うから抽象化しよう」と考えずにFooメソッドをコピペして作る。抽象化はリファクタリングなのでテストに通ってから。
  • 4: コードをきれいにする
  • 5: 1に戻る

Liscovの置換原則

サブクラスYのオブジェクトはいつでもスーパークラスXのオブジェクトとして使えなければならない。さもないとユーザがあるX型の変数に入っているオブジェクトが実際にはY型であることを意識しなければいけないようになってしまう。

Nullを渡す

Javaのような実行時のnullに対するアクセスを察知できる言語なら、テスト用に作るのが面倒なオブジェクトが必要なときに単にnullを渡せばいい。必要なものは必要になったときに例外で教えてくれる。

影響の調査の仕方

影響スケッチを描く

変数と戻り値が変わる可能性のあるメソッドをまるで囲む。影響を矢印で書く。

よく設計されていればこれはシンプルになるはず。

_

依存性の排除によってカプセル化が壊れるケースがある。たとえばprivateを外すとクラスの中だけ調査していれば依存性を把握できたのが、パッケージ全体を見なければいけなくなったりする。依存性の排除はテストを書きやすくするための手段であり、目的ではない。同様にカプセル化も依存性をおいやすくするための手段であり目的ではない。著者はテストを優先する。

_

サードパーティのライブラリを直接呼んでいる部分はseamにできたはずのところ。サードパーティライブラリに密結合なせいでテストが出来ないとか本末転倒。ラッパーなどを使って疎結合にする。

後半の具体例は斜め読みできないから今度じっくり読もう。

2010-07-22

FAXを送る

僕がテキストデータとして持っている物をFAXで遅れという電話がかかってきたがFAXなんて持ってないし。というわけで検索してみてこういうサービスを発見:

【ビジネスに役立つ無料ツール】 Webブラウザから無料でFAX送信! 41カ国に送信可能な「MyFax Free」 -INTERNET Watch

ちゃんと送れるかどうか不安だったけど(プレビューもないし)ちゃんと送れたようだ。2枚送られてきたと言われてびっくりしたが単にサイズが合わなくて2枚にわかれたってことだそうな。ちゃんと届いたか質問したが、受け取った側の人が「FAXの機械を使わずにブラウザから送信した」ってことを理解するのに時間がかかった。まあそれくらい特に変なところもなく送られたってことか。あとブラウザは専門用語なのでインターネットって言わないと通じないんだね!

2010-07-21

Haskellで単にn回7を掛けるだけでもO(n ^ 2.6)の時間がかかる

追記: このタイトルはミスリーディングで、きっちり末尾再帰にすればO(n ^ 2)になります。


k.inaba (略) とりあえず多倍長とGCと原因切り分けませんか

http://shinh.skr.jp/m/?date=20100721#c01

ということでとりあえず多倍長計算だけしてみた。(追記: これじゃ末尾再帰じゃないからスタックが伸びていってしまうじゃん、と指摘された。光成さんの末尾再帰版のコードではO(n^2)になった。下の方に自分で書いた末尾再帰版を追記。)

import System

pow :: Integer -> Integer
pow 0 = 1
pow n = (7 *) $! pow (n - 1)

main = do
  args <- getArgs
  print $ (0 *) $ pow $ read $ args !! 0

ここでf(x) = (x ** a) * b, g(x) = c * x * xで、X軸はコマンドライン引数で与えるn、Y軸は処理にかかった秒数。下記のように作成した。

gnuplot> f(x) = (x ** a) * b
gnuplot> fit f(x) "result.txt" via a, b

(..snip..)

Final set of parameters            Asymptotic Standard Error
=======================            ==========================

a               = 2.60015          +/- 0.09175      (3.529%)
b               = 2.3844e-13       +/- 2.772e-13    (116.3%)

(..snip..)

gnuplot> g(x) = x * x * c
gnuplot> fit g(x) "result.txt" via c

(..snip..)

c               = 4.1331e-10       +/- 1.394e-11    (3.373%)

(..snip..)

gnuplot> plot f(x), g(x), "result.txt"

なおGHC 6.10.4を使った。

GCプロファイルとやらもやってみるか。

./a.out 200000 +RTS -s 
0
   7,493,614,152 bytes allocated in the heap
         644,664 bytes copied during GC
       2,084,040 bytes maximum residency (2 sample(s))
       1,049,272 bytes maximum slop
               5 MB total memory in use (1 MB lost due to fragmentation)

  Generation 0: 13674 collections,     0 parallel,  4.83s,  5.02s elapsed
  Generation 1:     2 collections,     0 parallel,  0.00s,  0.00s elapsed

  INIT  time    0.00s  (  0.00s elapsed)
  MUT   time    7.14s  (  7.35s elapsed)
  GC    time    4.83s  (  5.02s elapsed)
  EXIT  time    0.00s  (  0.00s elapsed)
  Total time   11.97s  ( 12.37s elapsed)

  %GC time      40.4%  (40.6% elapsed)

  Alloc rate    1,050,088,044 bytes per MUT second

  Productivity  59.6% of total user, 57.7% of total elapsed

GCが処理時間の40%を食っていることはわかった。他の見所がよくわからない。


こう書き換えてみる。多倍長演算ではあるが、桁数がO(n)で増えていかないようにしたのだ。

pow n = (77777777777777777777 +) $! pow (n - 1)

実行時間が短くて、イニシャルコストがグラフ上ではっきり見えるくらいあるのはフィッティングとしてどうなのかという気がするが、まあO(n ^ 2.6)じゃなくてO(n ^ 2)だと言っていいだろう。え?O(n ^ 2)???

a               = 1.99989          +/- 0.114        (5.703%)
b               = 2.13455e-12      +/- 3.064e-12    (143.5%)
c               = 2.13161e-12      +/- 4.891e-14    (2.295%)

GCにはあんまり差がない。

./a.out 200000 +RTS -s 
0
      28,422,680 bytes allocated in the heap
           6,416 bytes copied during GC
       2,084,040 bytes maximum residency (2 sample(s))
       1,048,824 bytes maximum slop
               5 MB total memory in use (1 MB lost due to fragmentation)

  Generation 0:    45 collections,     0 parallel,  0.02s,  0.02s elapsed
  Generation 1:     2 collections,     0 parallel,  0.01s,  0.01s elapsed

  INIT  time    0.00s  (  0.00s elapsed)
  MUT   time    0.05s  (  0.06s elapsed)
  GC    time    0.03s  (  0.03s elapsed)
  EXIT  time    0.00s  (  0.00s elapsed)
  Total time    0.08s  (  0.09s elapsed)

  %GC time      35.1%  (33.7% elapsed)

  Alloc rate    538,644,986 bytes per MUT second

  Productivity  64.0% of total user, 59.0% of total elapsed

Haskell難しいなぁ。よくわからない。


最初のコードは末尾再帰じゃないじゃないかと指摘されたので書きなおしてみたらO(n ^ 2)になりました。

import System

pow :: Integer -> Integer -> Integer
pow x 0 = x
pow x n = pow (7 * x) (n - 1)

main = do
  args <- getArgs
  print $ (0 *) $ pow 1 $ read $ args !! 0

2010-07-20

海の哺乳類展に行ってきた

f:id:nishiohirokazu:20100719124244j:image

イッカク!これは1本だけある歯だそうな。超出っ歯。

続:Haskellのfibが遅い件

とても勉強になる流れなのでとりあえずざっくりとまとめる

2010-07-18

Google Codeにコードをコミットする

Mercurialなどでpushする際のアカウントには自分のGoogleアカウントのメアドを入れるけども、パスワードにはGoogleアカウントのパスワードではなく

https://code.google.com/hosting/settings

で見られるパスワードを使う。何が目的なのだろう?

Murotoのソースコードを公開しました

MurotoPongのコードとMurotoTesterのコードを公開しました

http://code.google.com/p/muroto/

MurotoPong:

MurotoTester:

ライブラリは個別のプロジェクトに入れずに /libs/muroto/に入れてあるのだけども、適宜プロジェクト内からln -sするなりコピーするなりして使ってください、って説明をどっかに書かなきゃいけないな。あとcocos2dのソースは配布していないのでその辺も解説書かなきゃ。続きはまた明日かな。

2010-07-15

558文字1行のPythonで書かれたBrainf*ckインタプリタ

http://gist.github.com/476940

もう3年も前の PythonでBrainf*ckインタプリタ(それ1行で書けるよ)の話なんだけど、動かないまま放ったらかしにしていたのを思い出したので修正してみた。まあ、空白文字を取り除く前のコードも残っているし、圧縮に使ったプログラムも残っているので実質的に作り直したのは変換前のコードがコマンドライン引数で指定されたプログラムを実行するようにしたことと、空白文字を取り除くプログラムを作り直したことくらい。以前空白文字を取り除くプログラムを作ったときは構文木にしてから空白なしで戻してやったんだけど、そんなことしなくても頭から1文字ずつ取り除きながらテストを走らせて壊れない空白を全部取り除くだけでいい。らくちん。

Hacker's Cafe Blog: The shortest oneline brainf*ck interpreter in python (558 characters)

portでtuareg-modeをいれたらemacsclientが動かなくなった

ぐっへり。お片付けは苦手なのである。

$ emacsclient -s /tmp/emacs501/server tmp.txt

ってやれば動く。「/tmp/emacs501/server」の部分の名前がなんかで書き換わってしまったのかなぁ。

$ export EMACS_SERVER_FILE=/tmp/emacs501/server
$ emacsclient tmp.txt
emacsclient: error accessing server file "/tmp/emacs501/server"

ぐへー。

あー、これは

$ emacsclient -f /tmp/emacs501/server tmp.txt
emacsclient: error accessing server file "/tmp/emacs501/server"

この挙動で、やるべきなのは-sか。

あー、しかもそれで動かしてもファイル名が -dirになってたり、C-x #してもemacsclientが終了しなかったり、ずたずただ。どうしたらいいんだこれ。

あーあーわかった

/Applications/Emacs.app/Contents/MacOS/bin/emacsclient tmp.txt

これなら今まで通り動く。

$ which emacsclient
/opt/local/bin/emacsclient
$ emacsclient --version
emacsclient 23.2
$ /Applications/Emacs.app/Contents/MacOS/bin/emacsclient --version
emacsclient 22.2.50

ということらしい。

2010-07-13

Haskell Quizの解答編を書いた

Hacker's Cafe Blog: Haskell Quiz Answer

英語の練習がてら長々と書いているけど、ざっくりとまとめると

  • Haskellでは値の定義のオーバーロードができる
    • showとか定義したことあるよね
  • 返り値の型でオーバーロードされた定義から選択することが可能(引数の型が同じで帰り値の方が違う関数をオーバーロードできる)
  • しかも引数を取る必要もない
  • (+) や (==) は t -> t -> t なので x + (1::Int) は x を (x::Int) にする効果がある
  • 0などの数値リテラルは (Num a) => a なので (0::Int) にも (0::Integer) にもなりうる

というわけでaやbはIntとして評価した場合とIntegerとして評価した場合で異なる値になる変数で、cがInt、dがIntegerで演算によって適当にaやbの型をコントロールしていたのでした。

Globalization is not a choice but a fact

何気なく隣の記事(東京は金融とか、そんな事は忘れましょう。 - Oh, you `re no (fun _ → more))を見てそこで引用されていた文章に吹いた。

「覚醒なんかしたくない、背伸びしてグローバル化したくない」が日本人のマジョリティーではないか?

「背伸びしてグローバル化したくない」だって!!

タイトルの「Globalization is not a choice but a fact(グローバリゼーションは選択肢ではなく、事実だ)」ってのはライス国務長官のダボス会議での発言なわけだが、かなり端的にグローバリゼーションに対する誤解を言い当てている。グローバリゼーションとは、インターネットの発明と、特にeコマースの発明が引き起こした社会構造の変化なんだ。つまりfactだ。個別の企業がグローバリゼーションを選択するとかしないとか言えるような選択肢ではない。

例を上げて説明しよう。たとえばあなたが食器メーカーで、今まで近くの飲食店に食器を卸してぼちぼちの利益をあげてたとする。別にグローバリゼーションなんか自分に関係ないし、今まで通りでいいや、と思っていたとする。しかしもしかするといま自分の顧客のカフェ店主はインターネットで北欧の聞いたこともないメーカーの食器を見て「こっちの方がいいな」と思っているかも知れない。毎年安定していた売上が、来年はいきなり半減するかも知れない。これがグローバリゼーションだ。あなたが「グローバリゼーションなんかしなくていいや」などと言って対策を取らないでいる間に世界の何処かの競合他社がコマを進めているかもしれない。あなたが何もしなくても、グローバリゼーションは止まらない。あなたが何もしないことで変化が止まるのではなく、あなたが変化に取り残されるだけだ。生命の歴史において、生き残るって来たのは一番強い生物ではない、一番変化に適応できた生物だ。変化に適応できなければティラノサウルスでも絶滅するんだ。

そういう話をしているのに「やだ、グローバリゼーションしたくない!」なんて言われたら「なに寝言いってるんだ、さっさと起きろ」と言いたくもなるだろうな。

もちろん、日本って国は極東の小さな島国の中だけで日本語を話す人間が1億人以上ひしめいているわけだから、日本人だけを相手にするビジネスもある程度はあるだろう。シンガポールは公用語が4つある国だったが、8割が中国人だからやっぱり中国人街の店員とかには英語の話せない人もいたよ。だから英語が話せないままでも、それなりに職はあるんじゃないのかな。だから、どーーしても英語を勉強したくないのであれば、英語を使わない職で生きていけばいい。どうしてもパソコンの操作が覚えたくないならパソコンを使わない仕事につけばいいだけなのと同じ。まあ。僕は僕の価値観で考えた結果、どう考えても英語を学ぶコストの方が学ばないことで引き受けるリスクよりも小さいだろ、と思うわけだが、そりゃあくまで僕の解釈なので同意できないなら同意しなくていいんじゃない?

Twitterから転載

あの記事を書いたモチベーションは「時流に疎い僕でもこれからの時代英語力は重要だろうと思って自主的に勉強しているというのに、会社から明示的にゴールを与えられても勉強しない人ってなんなの」であって「英語を学ぶの嫌なら転職しろよ」ではない。日本語でも伝わらない。

当社はこれからiPhoneアプリに命運をかけます!なのでObjCを勉強してください→いやです、でも転職もしません!→はぁ?という流れなら共感を得られるのに「英語」になると共感が得られないあたり日本人の英語コンプレックスは根強いなぁ。どう考えても英語のほうが活用しやすい知識なのに。

もう、価値観の違いとしかいいようがない。なんでそんなに英語を学ぶのが嫌なのかさっぱり理解できない。理解できないけど、まあ僕の人生じゃないし好きにすればいいんじゃない?

僕もあまり英語は得意ではない。若いうちにもっと英語を勉強すればよかったと思う。しかし、今後の人生の中で今が一番若いんだ。過去は変えられない。変えられるのは今からだ。僕は今そう考えている。

ぐぐれかしこ

丁寧に「ググレカス」って言う方法はないか、という話題で。

ご存知でしたら申し訳ございませんが、最近わたくしグーグルというアメリカの面白いホームページを見つけまして、ご質問の件におきましてもグーグルをお試しになるとよいかもしれません。今後ともご愛顧のほどよろしくお願いいたします。ぐぐれかしこ。

nishio/nishio hirokazu 2010-07-06 10:08:10 26 favs

Twitterから転載。

2010-07-12

今日の昼ごはん(高階関数クイズの解答)

問題編はこちら。まだ解いていない人はこちらを先にみてください。高階関数クイズ - Oh, you `re no (fun _ → more)

ネタバレ防止に

1

2

4

8

16

32

64

さすがに関数適用が左結合性なあたりは十分承知しているので2 * nになるわけがないじゃん、というところまではすぐわかったのだが、落とし穴を飛び越えた着地先にもう一つ落とし穴があっておもいっきりはまってしまった。

twiceをt, 引数の関数をn回適用する関数を<n>と書くことにすると

t = <2>
t t = <2> <2> = <2 ** 2> 
-- これがたまたま同じ2同士の演算なので勘違いしやすい。
-- あと<2 * 2>という解釈もできてしまう罠
t t t = (t t) t = <4> <2> = <2 ** 4> = <16>
-- <4 * 2>だと思った人はここでぶつかる。
-- これを<4 ** 2>だと思い込むと二つめの罠
t t t t = (t t t) t = <16> <2> = <2 ** 16> = <65536>
-- <16 ** 2>だと勘違いすると256と答えてしまう。

うん、まあ、あっさりと256って答えて落とし穴にはまった。

罠は2つ重なっているわけだ。まず関数適用の結合順序をぼんやりとしか考えていない人は(t t t t)を(t (t t t))だと勘違いする、と。数値で言うなら(2 *)と見せかけて(2 **)な罠。twiceって名前から間違った連想をしてしまいがち。しかも 2 * 1 == 2 ** 1, 2 * 2 = 2 ** 2 だから最初の2つはその解釈でも成立してしまう。ちゃんと問題文を見ていれば(t t t)が<8>にならないところで正されるはず。次に(** 2)と(2 **)が2と4に関してイコールなのが罠。2 ** 2 = 2 ** 2, 2 * 4 == 2 ** 4が成り立つので正解は 2 ** 16 なのに 16 ** 2 と答えてしまう。これもちゃんと問題文を見ていれば2 ** 1 /= 1 ** 2 だからわかったはずなんだけどな…。

2010-07-11

Porco Rossoなどを買った話

amazon.co.ukからの買い物の実例、2つ目(1つ目はAmazon.co.ukでDVDを買うと安いという話)

先日放送していた「紅の豚」、Twitterのタイムラインが盛り上がっていたのに僕は見れなかったのでカッとなって、紅の豚と隣に並んでいたカリオストロの城を買ってしまった(笑)

あと、ついでなので前から買おうと思っていたミシェル・ゴンドリーの作品集も購入。ミシェル・ゴンドリーを知らない人はぜひ一度下の動画を見るといい。どうやってこんな動画を作ったんだろう、って気になって、高解像度で見たいと前々から思っていたんだ。

http://www.youtube.com/watch?v=CBgf2ZxIDZk

日本で買うと4800円する。けどイギリスで買えば安い。

さて、そろそろ本題、結局幾らかかったのかというと、3点で22.85ポンド、3054円に送料が6.56ポンドの877円。

7/5に注文したときは、発送予定が7/6, 到着予定が7/26というメールがきたが、昨日7/10に家のポストを見たらもう投函されていた。

Delivery estimate: 26 July 2010
Dispatch estimate for these items: 6 July 2010 

前回も1月28日に注文して2月4日到着だったので1週間弱ですな。

そしてDVDはあっさりMacBookで見れたのであった。前回同様。あっさりうまく行き過ぎて記事に書く内容があんまりなかった。

2010-07-08

今日のよくわからない英語

This PEP proposes syntactic sugar for use of the ``super`` type to automatically construct instances of the super type binding to the class that a method was defined in, and the instance (or class object for classmethods) that the method is currently acting upon.

これってどう解釈したらいいんだろう。最初は[the super type binding]という名詞かと思ったんだが、そうすると construct O to something になるわけだな。それよりtypeとbindingの間で切って

to automatically construct 
  instances of the super type,
    (binding to the class that a method was defined in), 
  and the instance 
    that the method is currently acting upon.

になるのか?字面だけみるとそれもいい気もするが、意味がよくわからない。

2010-07-07

「仕事の出来る人」とは

自分の所属している組織がさ「今後の業務にスキルXが必要です。なのでスキルXを習得してください。」って決定した場合に、「仕事の出来る人」ってのは

  • 1 こんなこともあろうかとスキルXをすでに習得している
  • 2 今はスキルXを持っていないが、すぐに習得する
  • 3 スキルXの習得にコストを割くことが自分の為にならないと判断し、すぐにスキルXが必要とされない組織に転職する
  • 4 スキルXを習得するよりもより効率の良い業務形態や手法を提案し、説得し、組織の決定を変更させる(追記: thanks えるん)

のどれかだと思うんだ。組織の決定が正しいかどうかを議論するというのはおかしい。組織の決定に納得がいかないのであればさっさと3か4を選べばいい。3や4を選ぶのに必要な勇気やスキルがない上に、2を選択してスキルXを習得することもできない人、仕事ができない人と呼んで差し支えないんじゃないか。

ちなみに楽天が英語を公用語にした件のことだが。

2010-07-06

Haskell Quizに関して追記

Hacker's Cafe Blog: Haskell Quiz

($)を再定義していないって書いていなかったのは、素でうっかりと…。なんというか「一意に決まる」って言わない方がよかったかなぁ。こういうケアレスミスで余詰めが発生してしまうとか僕にはありがちすぎる。

前半がまるごとダミーだなんてことはなくて、あとそんな演算子が再定義できる言語ならなんでもできるようなことだったらクイズになんかしなくて、一応僕としてはHaskellのHaskellらしい機能を使っているつもりだったりするわけだ。

あと、この問題を聞いて id:n_shuyo さんに「PHPとかだと簡単に作れそうですね」とコメントされたのが一般論としては結構すばらしい洞察かと思う。PHPやPerlJavaScriptで「数学的に考えると変な挙動」を簡単に起こせるのはなぜか。

// JS
a = "9"
b = 10
c = "100"
console.log(a < b) // true
console.log(b < c) // true
console.log(c < a) // true

それは、プログラミング言語が数学的な振る舞い以外に色々な余計なことをするから。そのほうが便利だろうと思って、良かれと思っておせっかいを焼くから。この場合「文字列と数値を比較したときに勝手に数値に変換する」ってのね。まあ、実際にそれが便利であるケースの方が多いんだろうけども、便利な道具を深く理解しないで使っていると複雑なケースで手を咬まれるよね。そういう複雑なケースを作ってクイズにしているつもりだったりする。つまりそういうHaskellのPHPっぽい部分はどこなのかって考えるとヒントになるのかなーとか。

Google Gadgetを作る

気が向いたら作ろうと思って2年ほど放置していたガジェットを作る。

XMLをちょろっと書くだけだからさほど難しくなかった、

が、

間違ったXMLがキャッシュされてしまったのをクリアする方法がわからん!というわけで

Rule('/gg/def<dummy>', endpoint='google_gadget_definition'), 

ってな感じでURLを自由に変えられるようにしてキャッシュをクリアしたくなったら名前変更することにした!

自分のサイトにガジェットを追加

うんうん、できた。なんか白い枠が出てるけどそれは本質的じゃないからまた今度気が向いた時でいいや。

2010-07-05

デジタルネイティブに送る言葉

18年ROMれ



参考文献: 小学3年生の8歳の女の子が深夜にニコニコ生放送…ネットで話題騒然。こう言うのみるとやはりある程度のアウトプットに関しては年齢制限をかけるとか個別に親の承認が必要とかにする方がいいのかもなぁと思う。でも技術的にすごい中高生もいるしなぁ。悩ましい。

2010-07-02

今日の昼ごはん

紅の豚のDVDを買う

Porco Rosso [DVD]

7ポンドだから133 * 7で931円で、免税で810円で、送料が503円掛かるのでしめて1313円也。

2010-07-01

今日の昼ごはん

  • 二人の子どもがいる。「二人のうちのどちらかは男の子ですか」と質問して「はい」という返事があった場合、その男の子ではない方の子供が男の子である確率は1/3
  • 「二人のうちどちらかは月曜日生まれの男の子ですか」と質問して「はい」という返事があった場合の、その男の子ではない方の子供が男の子である確率は13/27
  • なぜ確率が上がったのか?「月曜日生まれ」というところに情報があるのか?
  • 性別を特定する情報の無い質問「二人のうちのどちらかは阪神ファンですか」の解答が「はい」であっても、阪神ファンじゃない方の子供が男である確率は1/2のまま。
  • 性別を特定する上で役に立たない情報「月曜日生まれ」を混ぜたせいで単に「男の子ですか」なら情報が得られた火曜日や水曜日生まれの男の子がいるケースで情報が得られなくなった。その結果、答えを聞いたあとの確率が元々の確率である1/2に近づいた。
  • 端的に言えば「情報が増えたから確率が上がったのではなく、情報が減ったから確率があまり変化しなかった」

あと昨日の昼ごはんにパッチを当てたり、なぜイスラム教では豚を食べてはいけないのか、とかC関数をラップしてOCamlに接続する方法 (How to wrap C functions to OCaml)とか、HaskellBang patternsとか。

Connection: close