@@ -3,4 +3,156 @@ package scalatutorial.sections
33/** @param name higher_order_functions */
44object HigherOrderFunctions extends ScalaTutorialSection {
55
6+ /**
7+ * = Higher-Order Functions =
8+ *
9+ * Functional languages treat functions as ''first-class values''.
10+ *
11+ * This means that, like any other value, a function
12+ * can be passed as a parameter and returned as a result.
13+ *
14+ * This provides a flexible way to compose programs.
15+ *
16+ * Functions that take other functions as parameters or that return functions
17+ * as results are called ''higher order functions''.
18+ *
19+ * = Motivation =
20+ *
21+ * Consider the following programs.
22+ *
23+ * Take the sum of the integers between `a` and `b`:
24+ *
25+ * {{{
26+ * def sumInts(a: Int, b: Int): Int =
27+ * if (a > b) 0 else a + sumInts(a + 1, b)
28+ * }}}
29+ *
30+ * Take the sum of the cubes of all the integers between `a`
31+ * and `b`:
32+ *
33+ * {{{
34+ * def cube(x: Int): Int = x * x * x
35+ *
36+ * def sumCubes(a: Int, b: Int): Int =
37+ * if (a > b) 0 else cube(a) + sumCubes(a + 1, b)
38+ * }}}
39+ *
40+ * Take the sum of the factorials of all the integers between `a`
41+ * and `b`:
42+ *
43+ * {{{
44+ * def sumFactorials(a: Int, b: Int): Int =
45+ * if (a > b) 0 else factorial(a) + sumFactorials(a + 1, b)
46+ * }}}
47+ *
48+ * Note how similar these methods are.
49+ * Can we factor out the common pattern?
50+ *
51+ * = Summing with Higher-Order Functions =
52+ *
53+ * Let's define:
54+ *
55+ * {{{
56+ * def sum(f: Int => Int, a: Int, b: Int): Int =
57+ * if (a > b) 0
58+ * else f(a) + sum(f, a + 1, b)
59+ * }}}
60+ *
61+ * We can then write:
62+ *
63+ * {{{
64+ * def id(x: Int): Int = x
65+ * def sumInts(a: Int, b: Int) = sum(id, a, b)
66+ * def sumCubes(a: Int, b: Int) = sum(cube, a, b)
67+ * def sumFactorials(a: Int, b: Int) = sum(factorial, a, b)
68+ * }}}
69+ *
70+ * = Function Types =
71+ *
72+ * The type `A => B` is the type of a ''function'' that
73+ * takes an argument of type `A` and returns a result of
74+ * type `B`.
75+ *
76+ * So, `Int => Int` is the type of functions that map integers to integers.
77+ *
78+ * = Anonymous Functions =
79+ *
80+ * Passing functions as parameters leads to the creation of many small functions.
81+ *
82+ * Sometimes it is tedious to have to define (and name) these functions using `def`.
83+ *
84+ * Compare to strings: We do not need to define a string using `val`. Instead of:
85+ *
86+ * {{{
87+ * val str = "abc"; println(str)
88+ * }}}
89+ *
90+ * We can directly write:
91+ *
92+ * {{{
93+ * println("abc")
94+ * }}}
95+ *
96+ * because strings exist as ''literals''. Analogously we would like function
97+ * literals, which let us write a function without giving it a name.
98+ *
99+ * These are called ''anonymous functions''.
100+ *
101+ * == Anonymous Function Syntax ==
102+ *
103+ * Example of a function that raises its argument to a cube:
104+ *
105+ * {{{
106+ * (x: Int) => x * x * x
107+ * }}}
108+ *
109+ * Here, `(x: Int)` is the ''parameter'' of the function, and
110+ * `x * x * x` is it's ''body''.
111+ *
112+ * The type of the parameter can be omitted if it can be inferred by the
113+ * compiler from the context.
114+ *
115+ * If there are several parameters, they are separated by commas:
116+ *
117+ * {{{
118+ * (x: Int, y: Int) => x + y
119+ * }}}
120+ *
121+ * == Anonymous Functions are Syntactic Sugar ==
122+ *
123+ * An anonymous function `(x1: T1, …, xn: Tn) => e`
124+ * can always be expressed using `def` as follows:
125+ *
126+ * {{{
127+ * { def f(x1: T1, …, xn: Tn) = e ; f }
128+ * }}}
129+ *
130+ * where `f` is an arbitrary, fresh name (that's not yet used in the program).
131+ *
132+ * One can therefore say that anonymous functions are ''syntactic sugar''.
133+ *
134+ * == Summation with Anonymous Functions ==
135+ *
136+ * Using anonymous functions, we can write sums in a shorter way:
137+ *
138+ * {{{
139+ * def sumInts(a: Int, b: Int) = sum(x => x, a, b)
140+ * def sumCubes(a: Int, b: Int) = sum(x => x * x * x, a, b)
141+ * }}}
142+ *
143+ * = Exercise =
144+ *
145+ * The `sum` function uses linear recursion. Complete the following tail-recursive
146+ * version:
147+ */
148+ def tailRecSum (res0 : Int , res1 : Int ): Unit = {
149+ def sum (f : Int => Int , a : Int , b : Int ): Int = {
150+ def loop (x : Int , acc : Int ): Int = {
151+ if (x > b) acc
152+ else loop(x + res0, acc + f(x))
153+ }
154+ loop(a, res1)
155+ }
156+ sum(x => x, 1 , 10 ) shouldBe 55
157+ }
6158}
0 commit comments