python3x: lambda function

[ラボ](http://cs61a.org/lab/lab02/)をやっていたら`lambda function`を見かけたので復習の意味も込めて。

#Lambda Function

一言で言うとlambdaを使えば関数を簡単に適当な変数にアサインすることができる。

##定義

>
_bind a function to a name using the same syntax and assignment statement._

まずは以下のexpressionについて考えてみる。

```
>>> x = 10
>>> square = x*x
>>> square
100
>>> square = lamnda x: x*x
>>> square
<function...>
>>> square(4)
16
>> square(10)
100
```

講義スライドを参考に簡単に図にまとめてみた。

![Screen Shot 2016-02-07 at 8.28.42 PM.png](https://qiita-image-store.s3.amazonaws.com/0/87666/40da4782-623e-192e-7c7f-fef2ad403cf3.png)

##`def`と`lambda`の違い

上の例を参考に違いをまとめると:

>
- _Both create a function with the same domain, range and behavior._
- _Both functions have as their parent the frame in which they were defined._
- _Both bind that function to the name square. (but in a different way: Lambda first creates the function with no name and it's the assignment statement that binds that function value to the name "square" whereas in the def statement, both of those things happen automatically, all as a byproduct of executing the def statement_
- _Only the def statement gives the function an intrinsic name._
![Screen Shot 2016-02-07 at 8.45.38 PM.png](https://qiita-image-store.s3.amazonaws.com/0/87666/e91e3114-3443-ae60-bea8-5b3c655dcae8.png)

基本的な動作に関してはそこまで大きい違いはない。では結局何に違いがあるのだというとそれは[Environmental diagram](http://inst.eecs.berkeley.edu/~cs61a/su10/resources/Joshua%20Cantrell%20Notes/8-EnvDiagrams.pdf)を書いてみると分かる。以下は講義スライドをスクショしたもの。

![Screen Shot 2016-02-07 at 8.51.23 PM.png](https://qiita-image-store.s3.amazonaws.com/0/87666/51fb5fdd-ea7d-baca-b28b-5078a4bf573e.png)

`def`で関数を作った場合その場で名前がふられるが`lambda`で関数を作った場合はその関数が出来上がっても`assignment statement`によって名前をアサインし終わるまでは名前を持っていないということ。つまりどういうことかというとpythonではわざわざ`def statement`を使って名前付けしなくても必要なときにその場で関数を作り上げてしまうことができる。

>_A lambda expression evaluates to a function that has a single return expression as its body._

![Screen Shot 2016-02-07 at 9.05.55 PM.png](https://qiita-image-store.s3.amazonaws.com/0/87666/e780dc7e-0d9b-bd43-0769-9d8c79afa96a.png)

`lambda expression`を実行した結果`lambda function`となって関数としての役割を果たす。この関数には先天的な名前を持っていないためpythonはシンプルに`<lambda>`として表記する。

```
>>> s = lambda x: x * x
>>> s
<function<lambda> at xxxxxxx>
>>> s(12)
144
```

それ以外で基本的な違いはない。

##Translating between named and anonymous functions

ふと思ったことなのだが（そしてどこかで書いたかもしれないが）`lambda x, y`と`lambda x: lambda y`という二つのexpressionを比べた時にparameterの数とargument以外で違いが浮かばなかった。

```
>>> adder = lambda x: lambda y: x + y
>>> adder2 = lambda x, y: x + y
>>> adder(1)(3)
4
>>> adder2(1,3)
4
```

ただreview seshに参加した時に`def`と`lambda`を比較することによってより違いがクリアになった。

![Screen Shot 2016-02-17 at 7.26.35 PM.png](https://qiita-image-store.s3.amazonaws.com/0/87666/b5cb2313-f67a-bfea-48b6-85d303e8ddb0.png)

考えてみたらこれは２個めの`lambda`は`def`でいう`def helper(y): return`と考えたら分かりやすい。

[Higher-Order Functions](http://qiita.com/weedslayer/items/c8d59b0a08673f8b50fe)もらくらくできてしまう。

```
def compose1(f,g):
    return lambdax : f(g(x))

f = compose1(lamnda x: x * x,
             lambda y: y + 1)

result = f(12) # 169
```

<a href="http://www.pythontutor.com/visualize.html#code=def+compose1(f,g%29%3A%0A++++return+lambda+x%3A+f(g(x%29%29%0A%0Af+%3D+compose1(lambda+x%3A+x+*+x,%0A+++++++++++++lambda+y%3A+y+%2B+1%29%0A%0Aresult+%3D+f(12%29&mode=display&origin=opt-frontend.js&cumulative=false&heapPrimitives=false&textReferences=false&py=3&rawInputLstJSON=%5B%5D&curInstr=0" target="_blank">PythonTutor.com</a>でより正確な関数の動きがわかる。

`compose1`関数の中にある`lambda x:f(g(x))`関数はglobal frameではなくf1 frameで作られることに注意。理由は`f`によって`compose1`が呼ばれて初めて`compose1`の中に入っていくからだ。`compose1`を呼んだ時には既にf1 frameを作っているので[p=g]なわけだ。もう一つ気づいた点は気づいた点は`compose1`関数の引数として渡している2つのラムダについて。個人的には`compose1`関数を呼んだ時に定義されるだろうと思っていたので[p=f1]と書いてしまったのだがどうやら上の`compose1(f,g)`と定義した時点で（何を受け取るか関係なく）変数に名前をアサインしているので後から`lambda`として投げ込んでも何を投げ込んでも結果[p=g]なのだと思う。そんなラムダも使い方を間違えると余計にわかりにくくなる。

>_lambda expressions are notoriously illegible, despite their brevity._

どういうことかというと上の関数を`compose1 = lambda f,g: lambda x: f(g(x))`と書くこともできるが完全に理解するのに多少時間がかかることが多いと。

##`lambda`の起源

どうやら`lambda`は当時のライターが数学の$ŷ. y * y$をという式をタイプライターで書けなかったことから生まれたとか。彼らはその表現を$Λy . y × y$と書き直した、というところから$λy . y × y$となり今でも$λ$という記号を観るようになったという。詳しくは[Peter Norvig](http://norvig.com/lispy2.html)を。

#lambdaを使って気づいたことを箇条書き

[lab02](http://cs61a.org/lab/lab02/)の問題をやっていて気づいたことを書いていきます。

##Question 1: WWPP: Lambda the Free

###Q1

```
>>> c = lambda: 3
>>> c()
3
```

選択肢としては
1. `None`をvalueとして出す (w/ some part missing?)
2. `3`を表示させるが`None`がvalue (=print)
3. `3`をvalueとして出す(=return)
くらいだろうか。ただ上の解説を見れば分かるようにlambdaには`return`が先天的に付属していると考えられているので当然`def c(): return 3`と同じ。つまり`3`を返す。

###Q2

```
>>> c = lambda x: lambda: print('123')
>>> c(88)
<function <lambda>.<locals>.<lambda> at 0x1013740d0>
```

100%あたっているという自信は無いが<a href="http://www.pythontutor.com/visualize.html#code=c+%3D+lambda+x%3A+lambda%3A+print(%22123%22%29%0Ac(88%29%0Ac(%29(88%29%0Ac(88%29(%29&mode=display&origin=opt-frontend.js&cumulative=false&heapPrimitives=false&textReferences=false&py=3&rawInputLstJSON=%5B%5D&curInstr=4" target="_balnk">pythontutor.com</a>から推測するに`c`は`lambda x:`that returns lambda: print('123`)`という構造になっていると読み取れる。~~恐らくそもそも二個目のlambdaは関数として呼ばれていないために~~__最初のラムダが二個目のラムダを関数として引き取ってその関数をそのまま返した__のだと思われる。これは後から気づいたことだが恐らくlambdaの中にlambdaを入れるという形を取ると最初のlambda関数が二個目のlambda関数を取って<function>として返すという特徴があるのではないかと思ってきた。*ちなみにラムダは関数も受け取れる（というかその使い方のほうが頻度が高いのかもしれない）。

```
>>> d = lambda f: f(4) # They can have functions as arguments as well.
>>> def square(x):
...     return x * x
>>> d(square)
16
```

つまり二個目も呼んであげればいいのだ。

```
>>> c = lambda x: lambda: print('123')
>>> c(88)()
123
```

しかし呼び方にも気をつける必要がある。なぜなら二個目のラムダには引数を受け取る機能がないからだ。`def foo(): print("123")`と同じである。よって以下を試みると:

```
>>> c(88)(3333)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: <lambda>() takes 0 positional arguments but 1 was given
```

エラーを吐いてしまう。改善方法としては単純に引数とを与えてあげればいいのだ。

```
>>> c = lambda x: lambda y: print("123")
>>> c(88)(333)
123
>>> c(88)()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: <lambda>() missing 1 required positional argument: 'y'
```

しかしこうすると逆にargumentとして受け取るものがないとエラーを吐いてしまうので注意。

###Q3

```
>>> t = lambda f: lambda x: f(f(f(x)))
>>> s = lambda x: x + 1
>>> t(s)(0)
3
```

詳しくは<a href="http://www.pythontutor.com/visualize.html#code=t+%3D+lambda+f%3A+lambda+y%3A+f(f(f(y%29%29%29%0As+%3D+lambda+x%3A+x%2B1%0At(s%29(0%29%0A&mode=display&origin=opt-frontend.js&cumulative=false&heapPrimitives=false&textReferences=false&py=3&rawInputLstJSON=%5B%5D&curInstr=0" target="_blank">pythontutor.com</a>を参考にして欲しいが、`t(s)(0)`は`(s)`と`(0)`片方ずつ`s`から`0`という順番で呼んでいくことと、`lambda`の持っている変数がそれぞれ何を指しているのかということを注意してみると理解しやすいかもしれない。

ちなみにlambda内の変数は`x`である必要はない。理由は受け取る際に自分が好みで指定した変数として受け取るからである。何もlambdaに限ったことではないが。

```
>>> t = lambda f: lambda y: f(f(f(y)))
>>> s = lambda x: x+1
>>> t(s)(0)
3
```

###Q4

```
>>> bar = lambda y: lambda x: pow(x, y)
>>> bar()(15)
TypeError: <lambda>() missing 1 required positional argument: 'y'
```

これは`lambda y`に対応するargumentが無いからである。`bar(some #)(15)`で動く。

###Q5

```
>>> foo = lambda: 32
>>> foobar = lambda x, y: x // y
>>> a = lambda x: foobar(foo(), bar(4)(x))
>>> a(2)
2
```

これは`lambda`というよりHigher-Order functions向けに作られてると思うのでそこまで解説する必要はなさそう。

###Q6

```
>>> b = lambda x, y: print('summer') # When is the body of this function run?
# Nothing gets printed by the interpreter

>>> c = b(4, 'dog')
summer

>>> print(c)
None
```

これは[pure non-pure functions](http://qiita.com/weedslayer/items/9ac165613bc896a1aaa1)を理解していればすぐ分かるはず。

##Question 2: Question 2: Lambda the Environment Diagram

```
>>> a = lambda x: x * 2 + 1
>>> def b(b, x):
...     return b(x + a(x))
>>> x = 3
>>> b(a, x)
```

上のコードをenvironmental diagramでかけるかという問題。

![Screen Shot 2016-02-08 at 1.29.03 AM.png](https://qiita-image-store.s3.amazonaws.com/0/87666/2e205ac5-8267-1a0f-17c3-0d6df1817821.png)

environmental diagramを書くときはframe名は必ずその関数の変数名ではなくその関数のintrinsic nameをつかってフレームを名付けることを忘れずに。

##Question 3: Lambdas and Currying

>_Write a function lambda_curry2 that will curry any two argument function using lambdas. See the doctest if you're not sure what this means._

```
 """Returns a Curried version of a two argument function func.
>>> from operator import add
>>> x = lambda_curry2(add)
>>> y = x(3)
>>> y(5)
8
"""
"*** YOUR CODE HERE ***"
return 
```

どの関数がどのvalueを受け取っているのかに注意しながら考えると簡単に解ける問題。例えば`lambda_curry2`関数は関数を引数として受け取っているということが`x = lambda_curry2(add)`よりわかる。次に変数`y`に数字を1つずつ入れて`8`が返ってきている。ということはlambdaは数字を2を受け取ってあとの処理は`lambda_curry2`が取ってきた関数を使えばいいでしょという結論にたどり着く。よって答えは`return lambda x: lambda y: func(x, y)`でオッケー。疑問はなぜ`return lambda x, z: func(x, z)`ではダメなのかということだったのだが、それはλを呼ぶときに`y = x(3)(5)`とするか`y = (3,5)`とするかの違いだけなのではないかと思っている。

```
>>> def lambda_curry(func):
...     return lambda x, y: func(x,y)
>>> from operator import add
>>> x = lambda_curry(add)
>>> y = x(3)(5)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: <lambda>() missing 1 required positional argument: 'y'
>>> l = x(3,5)
>>> l
8
```

残りの問題は一応解き終わっているのだが、[higher-order functions](http://qiita.com/weedslayer/items/c8d59b0a08673f8b50fe)が関わってくるのでそこをもうちょっと深く勉強して人に説明できるレベルにまで達したら更新することにします。

#Lambda w/ List Comprehension

`lambda`とlist comprehensionを使って中々実用的なことができることを発見したので備忘録がてら。

あまり効率的な探し方ではないが素数を探すときに`lambda`を使って以下のように書くことができる。

```
nums = range(2,30)
for i in range(2,8):
	nums = list(filter(lambda x: x == i or x % i, nums))
print(nums)
```

もう一つは適当な文章を見付けて来てそれをsentenceとしていれてあとは以下のスクリプトを動かせば単語ごとの文字数をリストにいれて返してくれる。例えば:

```
sentence = "I was a joke, and my life was a joke."
print(list(map(lambda x: len(x), sentence.split(" ")))) # [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
print(len(list(map(lambda x: len(x), sentence.split(" "))))) # 10 (=# of words)
```


#参考にしたリンク

-[Python: Lambda Functions](http://www.secnetix.de/olli/Python/lambda_functions.hawk)