LoginSignup
5
8

More than 5 years have passed since last update.

Python : lambdaの中でも再帰できた

Last updated at Posted at 2017-08-16

参考にした記事:Fizz Buzz問題で副作用と代入を抑えてみる【JavaScript、VB.Net、Python3、CommonLisp、Clojure、HSP、R言語】のコメント
Pythonでのワンライナー:再帰
Yコンビネータなんて複雑なものを作らなくても、関数に自分自身を受け取る引数があればいいのです。

lambdaの中に再帰は書けない(特別なことをしない限り)と思ってたんですけど、できるんですね。知らんかった。
いや、以前は読んでも理解できなくて脳内スルーしてたんだと思う。

記事を参考に自分でも階乗を書いてみました。

do = pack_to_tuple = lambda *x : x
case = unpack_and_evaluate_in_order_then_return_last = lambda x : x[-1]
otherwise = True

f = ( lambda x :
        case(     x == 0   and do( 1 )
              or otherwise and do( x * f( x - 1 ) )
             )
    )

f2 = ( lambda x :
       ( lambda f : f( f,  x ) ) ( lambda f, x :
                                     case(     x == 0   and do( 1 )
                                           or otherwise and do( x * f(f,  x - 1 ) )
                                         )
                                 )
     )

print(f(10), f2(10))
# 結果
3628800 3628800

※ 最初の三行は、Haskellっぽくガードっぽい条件分岐をするためのものです。
できた!

上の関数fと下の関数f2と同じ事をしています。
上の方は普通に再帰してます。こっちは普段やってるし理解できる。
下の方は?ちょっと難しい...
無名再帰で階乗を返す関数を作って、f2という名前をつけている、って感じでしょうか?

  • x と f を引数とし f(f,x) を返り値とする無名関数の引数 f に、
  • f と x を引数とし、x の値によって 1 または x*f(f,x-1) を返す無名関数を渡す
  • x を引数とする無名関数

何となくわかるようなわからないような...でも、上から下に機械的に変換することはできるので、必要になったときにはなんとかなりそうです。

違うよ、とか、こういうことだよ、とかあればコメントお願いします。

追記 これでいいのか

参考記事:【Python】lambdaで再帰

キーワード引数を使うと...

f3 = ( lambda x, f =  lambda f, x : case(     x == 0   and do( 1 )
                                        or otherwise and do( x * f(f,  x - 1 ) )
                                    )
       : f( f,  x ) 
     )

すっきり。何となく意味もわかりやすいような。勉強になりました。

5
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
8