pythonでY-combinator(Z-combinator?)

SICPも2章に入り、お約束らしいchurch数のあたりでプチ詰まり。

とか参考にしながら、後者のほうはperlのコードがあるから理解しやすいなぁとかいいながら読み進めるが、途中からさっぱりわからん。というより、Y-combinatorを理解しないと先に進めなさそうなので、Y CombinatorTuringとChurchの狭間でを行ったりきたりしながらくらいつく。

一通り理解した気がしたところで、perlのZ-combinatorをpythonで書いてみた。

まず階乗のpython2.5から導入されたという、3項演算子を使ってみた。

>>> def f(n):
...     return 1 if n < 2 else n * f(n-1)

こんな感じで書けるがなんか、、、perlの三項演算子のほうが好き。

で、早速Z-combinator

Z = lambda f: (lambda x : lambda y : f(x(x)))(lambda x : lambda y : f(x(x)))
fact = lambda f : lambda n :  1 if n < 2 else n * f(FORCE)(n-1)
FORCE = lambda a : a

実行

>>> Z(fact)(FORCE)(7)
5040

pythonはラムダ式が書けるのでperlよりはすっきりと書ける感じ。

一応pythonでもY-combinatorの形で実行したけどこれは無限ループした。

Z = lambda f: (lambda x : f(x(x)))(lambda x : f(x(x))) 

perlやpythonのばあい、クロージャにして無理やり遅延させるので

our $FORCE = sub { my $a = shift; $a };

評価が先送りになんのはわかるんだけど、schemeで

(f 5)

((lambda (x) (f x)) 5)

にすると遅延するのがよくわからんかった。書き方変えてるだけにしか見えないんだけど。これはクロージャと同じものなのだろうかそれとも評価の順番が違うからなのか?

pythonでグラフ表現

networkxで遊んでみた。なんか丁度いいネットワークモデルがあればよかったんだけど、なにも思い当たらないのでランダムに生成。 IPythonで。ちなみに僕のIPythonは-pylabオプションがつけてあるのでfrom pylab import *が不要。

In [1]: from random import choice,shuffle
In [2]: from networkx import *
In [3]: G=XGraph()
In [4]: sample = range(1,100)
In [5]: shuffle(sample)
In [6]: j=range(1,100)
In [7]: for i in sample:
   ...:     G.add_edge(i,choice(j))
   ...:
   ...:
In [8]: draw(G)

networkx

pythonでgzipファイルをバッファなして読む

gzipで圧縮した状態で3G超のファイルを読み込むのにpython2.2だと

import gzip,sys
for line in gzip.GzipFile("gzippped_txt.gz"):
    sys.stdout.write(line)

ができなくて焦ったがpython2.5だと問題なくOK。

pythonのスコープではまる

ちょっとはまった。結局オブジェクト作って解決しといたけど気持ち悪いので少し調べた。(でも未解決)

クロージャでカウンタを考える。Open Source WEBを参考に

perlだと

sub make_counter {
  my $c = $_[0] || 0;
  return sub { $c++ }
}

gaucheだとこんな感じ

(define (make-counter n)
  (let1 c n
    (lambda () (inc! c))))

でもpythonだとだめなの

def make_counter(n):
    c = n
    def counter():
        c = c + 1
        return c
    return counter

スコープの洗礼をうけた。参照できても代入できないのでglobalにする必要が。

def make_counter(n):
    c = n
    def counter():
        global c
        c += 1
        return c
    return counter

ctr = make_counter(5)
ctr()
ctr()

Traceback (most recent call last):
  File "C:\home\kzfm\test.py", line 10, in <module>
    ctr()
  File "C:\home\kzfm\test.py", line 5, in counter
    c += 1
NameError: global name 'c' is not defined

とかいってglobalでも駄目だ。

pythonでクロージャ

昨日の続き

ウィキペディアによるとリストを参照すればいいらしいので。

def make_counter(n):
    c = []
    c.append(n)
    def counter():
        l = c.pop()
        l += 1
        c.append(l)
        return l
    return counter

ctr1 = make_counter(5)
ctr2 = make_counter(3)
print "ctr1: ", ctr1()
print "ctr1: ", ctr1()
print "ctr1: ", ctr1()
print "ctr2: ", ctr2()
print "ctr2: ", ctr2()
print "ctr1: ", ctr1()

さて実行

$ ./make_counter.py 
ctr1:  6
ctr1:  7
ctr1:  8
ctr2:  4
ctr2:  5
ctr1:  9

おーできた。でもこれだったらクラスのほうが分かりやすいなぁ。

class Counter:

    def __init__(self,num):
        self.c = int(num)

    def count(self):
        self.c += 1
        return self.c

LEGBルールってなんか分かりにくいな。単なる慣れなのか?

gzipでMemoryError

pythonのgzipモジュールで読み込んで処理してたらメモリエラー。

MemoryError
gzip: sample.gz: invalid compressed data--format violated

おー、圧縮ファイル壊れてる。3G位ある圧縮ファイルで、つくんのに5日かかったのでちょっと凹んだ。

早く帰りたかったのでperlでちょこっと分割してtelnetで分散処理するスクリプト書いちゃったけど(これだと半日で終わるかな)。

家に帰ってきてからpythonでtelnetするモジュールを探してみた

みんなのPython Webアプリ編 を予約した

楽しみ。

ProductName みんなのPython Webアプリ編 [みんなのシリーズ]
柴田 淳
ソフトバンククリエイティブ / ¥ 2,604 ()
在庫あり。

pythonのdatetimeモジュール

6.10 datetime -- 基本的な日付型および時間型みながら。

>>> import datetime
>>> datetime.date.today()
datetime.date(2007, 7, 28)
>>> d = datetime.date.today()
>>> d.month
7
>>> d.day
28
>>> d.year
2007

で、matplotlibにはグラフを描きやすいようにmatplotlib.datesというモジュールがあって何日おきとか何年おきとかそんな感じの目盛りが簡単にうてる。

METAMORPHOSE 07 届いた

来月末に修善寺で行なわれるメタモのコンピが届いたヨ。

ProductName METAMORPHOSE 07
オムニバス
インディーズ・メーカー / ¥ 3,200 (2007-07-25)
在庫あり。

lindstromはやっぱええわ。あと、vvvv使いらしいtriponが気になる。

っていうかVJだけど、NintendoDSのタッチパッド使ったりとかWiiリモコンでVJやったりとかみると新しいデバイス使ってあれこれすんのは楽しそう。っていうか、DJの動きとかフロアの動きをゴニョゴニョして映像を生成したりとかはあるんだろうか?

IronPythonなんかつかってみると面白いことできるんじゃないかナァ。つうわけで、IronPython入れてみることにする。

Fedora7にmatplotlib-0.90.1をインストール

Fedora7用のrpmがないのでsrc.rpmをとってきて

rpmbuild --rebuild --define 'pyver 2.5' wxPython2.8-2.8.4.0-1.src.rpm

でいいと思うんだけど、rpm -Uvhで入れようとすると

エラー: 依存性の欠如:
    libiconv.so.2 は wxPython2.8-gtk2-unicode-2.8.4.0-1.i386 に必要とされています

と怒られる。so.2も在るし、ldconfigもきちんとしてるのに、、、、謎だ。

と思ったらこれrpmで入れてなかったわ。

結局tarballから入れた。