23. たのしい高階関数 λ
高階関数ってなに?
def twice(f:(Int => Int))(x:Int):Int = f(f(x))
関数 twice は
Int 型の引数を受け取り Int 型の値を返す関数 f
を受け取り、
Int 型の引数を受け取り Int 型の値を返す関数
を返す関数
24. たのしい高階関数 λ
高階関数ってなに?
def twice(f:(Int => Int))(x:Int):Int = f(f(x))
def add1(x:Int) = x + 1
> val add2 = twice(add1)(_)
add2: Int => Int = <function1>
> add2(3)
res1: Int = 5
25. たのしい高階関数 λ
高階関数ってなに?
def twice(f:(Int => Int))(x:Int):Int = f(f(x))
def add1(x:Int) = x + 1
Int 型の引数を受け取り
Int 型の値を返す関数
> val add2 = twice(add1)(_)
add2: Int => Int = <function1>
Int 型の引数を受け取り
> add2(3) Int 型の値を返す関数
res1: Int = 5
26. たのしい高階関数 λ
高階関数ってなに?
def twice(f:(Int => Int))(x:Int):Int = f(f(x))
def add1(x:Int) = x + 1
> val add2 = twice(add1)(_)
add2: Int => Int = <function1>
> add2(3) = twice(add1)(3) = add1(add1(3))
res1: Int = 5
38. たのしい高階関数 λ
高階関数を学ぶメリット
list.map(new Func1<Integer, Integer>() {
public Integer apply(Integer a) { return a * 2;}
}).filter(new Func1<Integer, Boolean>() {
public Boolean apply(Integer a) { return a >= 10;}
}).reduce(new Func2<Integer, Integer, Integer>() {
public Integer apply(Integer a, Integer b) { return a + b; }
});
54. たのしい高階関数 λ
リストを扱う高階関数
map 関数の実装
map :: (a -> b) -> [a] -> [b]
map _ [] = []
map f (x:xs) = f x : map f xs
ヘッダ テイル
55. たのしい高階関数 λ
リストを扱う高階関数
map 関数の実装
def map[B, That](f: A => B)
(implicit bf: CanBuildFrom[Repr, B, That])
: That = {
val b = bf(repr)
b.sizeHint(this)
for (x <- this) b += f(x)
b.result
}
56. たのしい高階関数 λ
リストを扱う高階関数
map 関数の実装(簡略化)
def map[B, That](f: A => B)
def map[A, B](f: A => Bbf:List[B] = {
(implicit ): CanBuildFrom[Repr, B, That])
val b = new :ListBuffer[B]()
That = {
val b = bf(repr)
b.sizeHint(this)
b.sizeHint(this) buff += f(x)
for (x <- this)
for (x <- this) b += f(x)
b.result
}b.result
}
64. たのしい高階関数 λ
リストを扱う高階関数
foldl / foldr 関数のイメージ
foldl f 0 [1,2,3,4] foldr f 0 [1,2,3,4]
f f
f 4 1 f
f 3 2 f
f 2 3 f
0 1 4 0
関数 f でリストを畳み込んで単一の値を返す。
左からと右からの畳み込み関数がある。
67. たのしい高階関数 λ
リストを扱う高階関数
foldl / foldr 関数の例
> let add x y = x + y
> foldl add 0 [1,2,3,4]
10
> foldr add 0 [1,2,3,4]
10
68. たのしい高階関数 λ
リストを扱う高階関数
foldl / foldr 関数の例
> let add x y = x + y
> foldl add 0 [1,2,3,4]
= add(add(add(add(0, 1), 2), 3), 4)
= add(add(add(1, 2), 3), 4)
= add(add(3, 3), 4)
= add(6, 4)
=10
> foldr add 0 [1,2,3,4]
10
69. たのしい高階関数 λ
リストを扱う高階関数
foldl / foldr 関数の例
> let add x y = x + y
> foldl add 0 [1,2,3,4]
10
> foldr add 0 [1,2,3,4]
= add(1, add(2, add(3, add(4, 0))))
= add(1, add(2, add(3, 4)))
= add(1, add(2, 7))
= add(1, 9)
= 10
70. たのしい高階関数 λ
リストを扱う高階関数
foldr 関数の実装
foldr :: (a -> b -> b) -> b -> [a] -> b
foldr k z = go
where
go [] = z
go (y:ys) = y `k` go ys
71. たのしい高階関数 λ
リストを扱う高階関数
foldr 関数の実装
foldr :: (a -> b -> b) -> b -> [a] -> b
foldr k z = go
where
go [] = z
go (y:ys) = y `k` go ys
foldr k z [] = z
foldr k z (y:ys) = k y (foldr k z ys)
72. たのしい高階関数 λ
リストを扱う高階関数
foldl 関数の実装
foldl :: (a -> b -> a) -> a -> [b] -> a
foldl f z0 xs0 = lgo z0 xs0
where
lgo z [] = z
lgo z (x:xs) = lgo (f z x) xs
73. たのしい高階関数 λ
リストを扱う高階関数
foldl 関数の実装
foldl :: (a -> b -> a) -> a -> [b] -> a
foldl f z0 xs0 = lgo z0 xs0
where
lgo z [] = z
lgo z (x:xs) = lgo (f z x) xs
foldl f z [] = z
foldl f z (x:xs) = foldl f (f z x) xs
74. たのしい高階関数 λ
リストを扱う高階関数
foldLeft 関数の実装 (Scala)
def foldLeft[B](z: B)(f: (B, A) => B): B = {
var acc = z
var these = this
while (!these.isEmpty) {
acc = f(acc, these.head)
these = these.tail
}
acc
}
75. たのしい高階関数 λ
リストを扱う高階関数
foldRight 関数の実装 (Scala)
def foldRight[B](z: B)(f: (A, B) => B): B =
if (this.isEmpty) z
else f(head, tail.foldRight(z)(f))
76. たのしい高階関数 λ
リストを扱う高階関数
Scala の foldRight 関数の注意点
scala> (1 to 10000).toList.foldLeft(0)(_ + _)
res0: Int = 50005000
scala> (1 to 10000).toList.foldRight(0)(_ + _)
java.lang.StackOverflowError
77. たのしい高階関数 λ
リストを扱う高階関数
Range の場合は大丈夫
scala> (1 to 10000).foldLeft(0)(_ + _)
res0: Int = 50005000
scala> (1 to 10000).foldRight(0)(_ + _)
res1: Int = 50005000
78. たのしい高階関数 λ
リストを扱う高階関数
Range の foldRight 関数の実装
def foldRight[B](z: B)(op: (A, B) => B): B =
reversed.foldLeft(z)((x, y) => op(y, x))
まさかの reversed !
Reversed は List 型を返すので、
List の foldLeft が使われる