パスワードを忘れた? アカウント作成
268229 journal

greenteaの日記: Pythonのlambda式は表現力不足? 2

日記 by greentea

http://hibari.2ch.net/test/read.cgi/tech/1287944631/
Pythonのlambdaが表現力不足だって?
代入が式じゃないとかいうけど、関数型言語なんて代入そのものがない場合だってあるんじゃないの?

ということで、いろいろ書いてみた。

# 階乗
fact = lambda n:(lambda f: f(f,n))(lambda g,i: i*g(g,i-1) if i>0 else 1)
 
# 内包表記を使わずに、
# for i in range(n):
#   f(i)
# に相当する関数を作る
# f(i) and False or g(g, i+1)の部分は[f(i)] and g(g, i+1)でもよい。
loop = lambda f,n: (lambda g: g(g, 0))(lambda g,i: i<n and (f(i) and False or g(g, i+1)))
# 使用例
loop(lambda x: sys.stdout.write('%d\n'%x), 3)
 
# 同様に、
# for elem in iterable:
#   f(i)
# に相当する関数。ここでitarableはインデックスで取り出しできない可能性もある
# (じゃないと、elemをiterable[i]として、上のと同じようにできる)
import itertools
foreach = lambda f, iterable: \
              (lambda term: \
                  (lambda it: \
                       (lambda g: g(g, it, it.next()))(lambda g, it, elem: elem is not term and (f(elem) or True) and g(g, it, it.next())))
                  (itertools.chain(iterable, [term])))([])
'''Comment: 表現力不足だって?というお題目で始めたが、ここは私の知識不足でなければ表現力不足だ。
Pythonには、例外をキャッチする式がないので、イテレータの終了を表すStopIteration例外を取得できない。
なので、終了を表す符号として、termに束縛した空リストを入れた。
比較部分は、同値性の比較elem != termではなく同一性の比較elem is not termを使っているので、仮にiterableの中に空リストが入っていたとしても誤動作しない。
が、それを実現するために、itertools.chainと[term]と[]が無駄に必要になり、lambdaが一段増えてしまった。
'''
 
# reduceをlambdaで実装。
# スレの方で、アキュムレータにリスト使ってることについて反応があったので、
# 今度はそういうことをしないでやってみた。
# けど、前述の理由で、無駄に空リストを入れないといけない。
my_reduce = lambda f, iterable, init: \
              (lambda term: \
                  (lambda it: \
                       (lambda g: g(g, it, it.next(), init))(lambda g, it, elem, acc: \
                                   acc if elem is term else g(g, it, it.next(), f(acc, elem))))
                  (itertools.chain(iterable, [term])))([])

ということで、表現力が十分とは言わないが、いろいろとできるんですよ、と。

読みづらい、もっと読みやすい方法では書けないのかって?
そんなときは、無理にlambdaなんか使わないで、for使うとか、名前付き関数使うとか、そういう方法が推奨されてますです。

この議論は賞味期限が切れたので、アーカイブ化されています。 新たにコメントを付けることはできません。
  • 規模でっかくなったら、その場でdef ... したほうがいいでしょうねぇ

    どの道ワンライナー的なのを除くと関数オブジェクトを変数(ラベル)に入れて使うわけだし...

    # ということでいいのかな?

    --
    M-FalconSky (暑いか寒い)
    • by greentea (17971) on 2010年10月28日 21時10分 (#1849294) 日記

      その通りです。

      なのですが、例えばインスタンスに属性を付け加えたいときや、ソートのキーに指定したいとき、
      foo.foo = lambda ...
      ls.sort(key=lambda ...)
      のように、直接関数を入れたくなります。

      また、lambdaでの対応が難しいほどに「規模が大きい」状態がRubyなどと比べて、すごく早く訪れます。

      Pythonでは、変数を作って値を代入する、2つ以上の式を順次評価する、例外を発生させる・受け取る、内包表記以外の方法でループを書くといったようなことが1つの式では出来ないorやりにくく、lambdaには1つの式でしか書けません。

      なので、そういう風に言われたりするのも、まぁ、分からなくはないのです……

      --
      1を聞いて0を知れ!
      親コメント
typodupeerror

最初のバージョンは常に打ち捨てられる。

読み込み中...