作者: 機械伯爵
日時: 2008/1/22(12:21)
 ども、機械す。

<lambda文>
> 昔Pythonに手を出そうとしましたが、それを知って愕然としました。

 昔と異なり、今では条件付き評価式でif-else分岐程度は出来ますし、内包記
法も充実してきましたので、昔ほどは不便ではないとは思うのですが、本格的な
ルーチンを記述しようとすると、外で別個にdef文で名前付きの関数を作ってお
くのが無難ですね。

 Python 3000ではexecが関数になるのでこれで理論上は全ての文が式として書
けるのですが、まぁ、書いてみればわかりますが、せっかくのPython自慢の読み
やすさが「だいなし」になるような、しかも「醜い」記述になります(苦笑)

 「シンプルに/エレガントに」書こうとすれば、結局名前つき、となるわけで
す。

<ブロック>
> Rubyのブロックは美化された高階関数です。
> 関数を引数に取るLisp関数のうち、圧倒的多数がひとつの関数しか取らないため、
> Rubyのブロックはひとつだけという設計上の決定に至ったとどこかで聞きました。
> 
> ブロックに複文が記述できる利点はやっぱり制御構造の抽象化です。
> 自分で制御構造の構文を作れる感覚です。

 Rubyの本を読み直して、自分が根本的なところで誤解しているような気がしま
した。

 ブロックというなら、Pythonの関数/手続きはすべてブロックです(ブロック
以外の関数は存在しません)

 ですから、Pythonのdef文は全てRubyで言うところのProc.new(or proc or 
lambda?)であり、したがってcallメソッドを全て介していると判断されて、
func()で呼び出しているわけです。

 よって、Rubyがすごいトコは、ブロックが使えるところというよりも、コレク
ションなどにブロックを受け取って手軽にループ構造を作るメソッドが充実して
いるところではないでしょうか。

 Pythonでも型を拡張すれば同様のことは可能だと思いますが、それは「共通の
書き方」ではなくなり、なじみの無い人には何をしているのかわかりづらくなる
可能性があります。

 これは、Pythonの方向性の問題もあると思いますので、後述します。

> たとえばHash#fetchはハッシュのキーに対応する値を得るメソッドですが、
> ブロックを持つことができます。
> ブロックはキーが存在しない場合のみに評価されます。
> だからブロック中にキーが存在しない場合の処理をごにょごにょ書けるのです。

 Pythonはシンボルが使えないので、こんな感じですか

d = {'one':1, 'two':2}
d.get('three') if 'three' in d else '%s is not found' % 'three'

 評価してませんから、キーは拾えません。

> 次の例は二次元配列のインデックスつきループを定義します。

 普通に二重ループで書くとこんな感じのモノですよね。

ary2 = [[1],[2,3],[4,5,6]]
mes = "ary2[%s, %s]=%s"
for x in range(len(ary2)):
  for y in range(len(ary2[x])):
    print(mes % (x,y,ary2[x][y]))

 Pythonの内包記法を使ってみると……

k = [
  [print(mes % (x,y,ary2[x][y]))for y in range(len(ary2[x]))]
  for x in range(len(ary2))
]

 ……わかりづらいですね、明らかに(笑)

 メソッドとして差し込んでみましょうか?

ary2 = [[1],[2,3],[4,5,6]]

class xList(list):pass

ary2 = xList(ary2)

xList.each_with_index_2dim = lambda self:[
    [print("[%s, %s]=%s" % (x,y,self[x][y]))
      for y in range(len(self[x]))
    ]
    for x in range(len(self))
  ]

ary2.each_with_index_2dim()

 ……う〜む、さらにわからん……
 やはりPythonでは、普通にループを書くが推奨されると思います。

> 例ではブロックの中身は1つの式ですが、当然複数の式が書けます。
> if等の条件分岐が式として値を持つのが地味に便利です。
> 
> 他にもソートの条件とかもブロックで指定します。

 Pythonはマルチパラダイムの言語であるので、色々(特に近頃は関数型が充実
……lambdaが消えなかったのもそのためかも)出来ますが、反面、一貫性のある
ルールで書こうとすると、古い時代の手続き型が基準になってしまうようです。

 Rubyがオブジェクト指向を貫いて、その方針に沿ったツールを厳選して揃えて
いるのとは、ある意味対照的です。

 ですから、プログラマが自分の書き方のポリシーを統一して何かしようとする
と、Pythonの方針に壁が見えてきます。

 オブジェクト指向ならSmalltalkやRuby、データフロー型ならAWKやPerl、関数
型ならLisp/SchemeやHaskellといった風に。

 そういった様々な言語を語る共通/説明言語として、今までPascalやCやJava
のコードが用いられてきましたが、Pythonはそれに代わる役割を果たせるのでは
ないかと思います。

 だから、これからのトレンドは「Python to 〜」ということで(笑)

 /機械伯爵/さて次は、初心者ブースへ乗り込むぞよ、と/