Python:lambdaで問題5に挑戦...しないでワンライナーに深入り...しない

[ソフトウェアエンジニアなら１時間で解けるべき問題５に挑戦](http://qiita.com/kota9/items/91e4fecfae550be8f109#comment-19767d72e87ae0c26afc)をごにょごにょしてたら、
コメントで[podhmo](http://qiita.com/podhmo)さんよりワンライナーいただきました。ありがとうございました。
(現物は[元記事](http://qiita.com/ttatsf/items/75ce84110c985ab68e93)を御覧ください。)

眺めてもさっぱり意味が分からないので、バラして自分で分かる形にしてみようとやってみました。

#のっけからまったく意味不明の流れ

```Python
(lambda f: (lambda x: x(x))(lambda y: f(lambda v: y(y)(v))))
```

ぐるぐるしてる感じは伝わってくるのですが...謎です。
そのままググってみたらYコンビネータというものだそうな。
無名関数のまま再帰できるんだそうです。
ごめんなさい。今はスルーさせていただきます。目が回ってきたので。

#自分に分かるように普通に名前を付けてやってみた
こんな感じでしょうか？　

+ 核心部分はコピペ。
+ Yコンビネータを取るにはどうしたら？を考える。
+ mapをリスト内包表記に変える練習。

```Python
c=(lambda xs:
	[ [xs[0]] ] if len(xs) <= 1 else
    __import__("itertools").chain(
        [ [xs[0], ""] + y for y in c(xs[1:]) ],
        [ [xs[0], " + "] + y for y in c(xs[1:]) ],
        [ [xs[0], " - "] + y for y in c(xs[1:]) ]
    )
)

print( "\n".join(
            [   x for x in
                [   "".join(str(y) for y in z )
                        for z in c(range(1, 10 ) )
                ]
                if eval(x) == 100
            ]
       )
)
```

+ すべての文字の組み合わせのリストのイテレータを返す関数cに
+ range(1,10)を適用して
+ 結合した文字列のうち
+ 評価したら100になるものを
+ printする

ということでしょうか。
自分も最初そうするのかなと思ったんですが、じゃあどうしたらいいかが分かりませんでした。勉強になりました。

ところで...
#~~def内には再帰関数を置けるが、lambda内には置けない~~
~~ようです。~~ できました。後述。

defでq_5_1の中にcを定義した下のはちゃんと動きました。

```Python
def q_5_1():
    def c(xs):
        return ([[xs[0]]] if len(xs) <= 1 else
                                  __import__("itertools").chain(
                                      [[xs[0], ""] + y for y in c(xs[1:])],
                                      [[xs[0], " + "] + y for y in c(xs[1:])],
                                      [[xs[0], " - "] + y for y in c(xs[1:])]
                                )
                )
    print("\n".join(
            [   x for x in
                [   "".join(str(y) for y in z )
                        for z in c(range(1, 10 ) )
                ]
                if eval(x) == 100
            ]
        )
    )

q_5_1()
```

lambdaで同じことをしようとするとうまくいきませんでした。


```Python
def pr(x):
    print x
    
q_5_2=(lambda:
    (lambda c=(lambda xs:
            [[xs[0]]] if len(xs) <= 1 else
            __import__("itertools").chain(
                [[xs[0], ""] + y for y in c(xs[1:])],
                [[xs[0], " + "] + y for y in c(xs[1:])],
                [[xs[0], " - "] + y for y in c(xs[1:])]
            )
        ):
            pr( "\n".join(
                    [   x for x in
                        [   "".join(str(y) for y in z )
                                for z in c(range(1, 10 ) )
                        ]
                        if eval(x) == 100
                    ]
                )
            )
    )()
)

q_5_2()
```

"NameError: global name 'c' is not defined"とか怒られました。
lambdaでは引数は外側の環境を参照するから自分自身は呼べないっていうことでしょうか...
Yコンビネータとかがあるのもこの辺と関係があるんでしょうか。

とはいえ、複雑なものは簡単な関数に分けて考えろというのがすごいH神の教え？なので、当面は特に困らないかもです。

※できました。

```Python3
# coding: utf-8

do = box = lambda *x : x
switch = unbox = lambda x : x[-1]
otherwise = True

q_5_2=( lambda :
        ( lambda c = ( lambda xs :
          ( lambda f : f( f, xs ) )(lambda f, xs :
              switch(
                   len(xs) <= 1 and do( [[xs[0]]] ) 
                or otherwise    and do( __import__("itertools").chain(
                                       [[xs[0], ""] + y for y in f( f, xs[1:])],
                                       [[xs[0], " + "] + y for y in f( f, xs[1:])],
                                       [[xs[0], " - "] + y for y in f( f, xs[1:])]
                                       )
                                      )
             )
            )
          ):
            print( "\n".join(
                [ x for x in
                  [ "".join(str(y) for y in z )
                    for z in c(range(1, 10 ) )
                  ]
                  if eval(x) == 100
                ]
               )
            )
         )()
    )

q_5_2()

```
さらに簡潔に：

```Python:
# coding: utf-8

do = box = lambda *x : x
switch = unbox = lambda x : x[-1]
otherwise = True

q_5_2 = lambda : (
    lambda c = lambda xs , f = lambda f, xs :
                            switch(
                                len(xs) <= 1 and do( [[xs[0]]] ) 
                                or otherwise and do( __import__("itertools").chain(
                                        [[xs[0], ""] + y for y in f( f, xs[1:])],
                                        [[xs[0], " + "] + y for y in f( f, xs[1:])],
                                        [[xs[0], " - "] + y for y in f( f, xs[1:])]
                                    )
                                )
                            )
            
            : f( f, xs ) 
        :
        print( "\n".join(
                [ x for x in
                    [ "".join(str(y) for y in z )
                        for z in c(range(1, 10 ) )
                    ]
                        if eval(x) == 100
                ]
            )
        )
    )()
    

q_5_2()

```