概要
- lambda 式がよく分かってない頃に書いた記事
- 今は Python についてはある程度使い慣れた
- でもほかの言語についてはまだ何尾進歩していないのでスタート地点を示す意味でもここで晒す
目的
- 複数の言語で無名関数の定義を比較して共通するイメージがあればそれを得る
現状
- 無名関数がよくわからん
- 無名関数? 匿名関数? Lambda 式? 関数リテラル? クロージャ?
- 「あっ、ここ無名関数使えばいい感じになるぞ」の感覚を得たい
- 現時点では一度きりしか使わない処理を書くときに便利、という程度の認識
複数の言語で比較してみる
- 名前の付いた関数を定義する際はどの言語でも(型の宣言の有無とかを除けば)だいたい同じだと思います。
- しかし無名関数に限っては言語ごとに独自のルールが際立つのでよくわからんという感じがあるように思えます。
- Python の場合はガッツリ lambda という単語が入ってきます。
lambda 変数名: 処理
>>> def my_add(a):
... return lambda x: x + a
...
>>> f = my_add(1)
>>> f(100)
101
>>> my_add(1)(2)
3
>>> (lambda s: 'hoge'+ s)('fuga')
'hogefuga'
- よく高階関数(
map
とか filter
とか)の第一引数に入れたりしますよね
Go の場合
- Go の場合は関数リテラルという名前がついています。
- 関数リテラルは定義の外にある変数にアクセスできます。
func(変数名 変数の型) 戻り値の型 {
return 戻り値
}
- 通常の関数の定義がこれなので、なるほど無名関数、という感じです。
func hoge(変数名 変数の型) 戻り値の型 {
return 戻り値
}
package main
import "fmt"
func main() {
x := 10
func(i int) {
fmt.Println(i * x)
}(2)
f := func(s string) int {
return len(s)
}
fmt.Println(f("hogege"))
}
mumei.go
という名前を付けて実行するとこうなります。
$ go run mumei.go
20
6
- 上の例で書いた
定義だけしておくパターン
って「無名なのに名前つけてるやん」って思ってしまったのですがどうなんでしょう。よくわかりません
- 関数として定義するか関数オブジェクトとして定義するかの違いみたいなものなんでしょうか?
- でも Go はクラスからオブジェクト指向ではないのでそれもまた違うのかなぁ…とよくわからなくなっている
- てか関数オブジェクトじゃなくて関数リテラルか。
- たぶんクロージャとしての性質が重要なんだよねたぶん
- あまり意識せずに無名関数使ってる言語ランキング1位(勝手なイメージ)
- JavaScipt と JQuery の根っこの違いを私自身が分かっていないので Web 風味な使い方には触れずに書きます。
function(引数名, 引数名, ...) {
}
var my_add = function(a, b){
return a + b;
}
var hoge = my_add(1, 2)
- あとは Go のときのように宣言時に引数を代入して実行することもできます。
var my_add = (function(a, b){
return a + b;
})(1, 2)
console.log(my_add);
- 定義するときは必ず上のように変数に代入するか、関数の引数として書いてやる必要があります。
var
で宣言しているところからもわかるように変数として宣言するからだと思います。
Elm の場合
- まだ文法をかじっている途中なのですがせっかくなので書きます。
\引数名 引数名 ... -> 式
- そもそも関数の定義のしかたが以下のようになっているのでこれもなるほど感があります。
関数名 引数名 引数名 ... = 式
> \x y -> x + y
<function> : number -> number -> number
> (\x y -> x + y) 1 2
3 : number
- 無名関数に名前を与えることで関数の定義とすることもできるみたいです。
> myAdd = \x y -> x + y
<function> : number -> number -> number
> myAdd 1 2
3 : number
\引数名 引数名 ... -> 式
関数名 引数名 引数名 ... = 式
- Elm と同じですね。いや逆か。
- REPL で一応試してみます。
Prelude> (\a b -> a + b :: Int) 1 2
3
::Int
で戻り値の型を明示する方が安全です。
- もう書きませんがこちらも無名関数に名前を付けて(等号で結ぶ)関数の定義とすることができます。
まとめ
- こうして見ると複数の言語に手を出してる割に全然理解してないなというのがよくわかります(泣)。
課題
- 定義と一番簡単な例しか見れていないので、使いどころまでは深堀りできませんでした。
- 高階関数を使うときに重要とかそういうのがあった気がするのでそこからまた勉強します。
- 言語を限定して掘り下げたいです。