Skip to content

Commit 4807317

Browse files
committed
Finish currying chapter
1 parent 0d78017 commit 4807317

11 files changed

+135
-109
lines changed

src/main/worksheets/f_Functions/b_higher_order_functions_2_exercise.sc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,12 @@ val maxLiteral: Int => String => Boolean = maximum => s => s.length <= maximum
1212

1313
acceptString("Foo", minLiteral(1))
1414
acceptString("Foo", maxLiteral(2))
15+
16+
17+
// Lost in parameter type lists? Type alias to the rescue!
18+
type Predicate = String => String => Boolean
19+
20+
val is: Predicate = oneString => otherString => oneString == otherString
21+
22+
acceptString("FooBar", is("FooBar"))
23+

src/main/worksheets/f_Functions/c_partially_applied_2_use_case.sc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33
*/
44
def acceptString(s: String, pred: String => Boolean): Boolean = pred(s)
55

6-
def min(minimum: Int): String => Boolean = (s: String) => s.length >= minimum
7-
def max(maximum: Int): String => Boolean = (s: String) => s.length <= maximum
6+
def min(minimum: Int): String => Boolean = s => s.length >= minimum
7+
def max(maximum: Int): String => Boolean = s => s.length <= maximum
88

99
/**
10-
* A function which applies a list of predicates to a string.
10+
* A function which returns a function which applies a list of predicates to a string.
1111
*/
1212
def any(predicates: (String => Boolean)*): String => Boolean =
1313
s => predicates.forall(pred => pred(s))

src/main/worksheets/f_Functions/currying_4_enables_syntactic_sugar.sc

Lines changed: 0 additions & 14 deletions
This file was deleted.

src/main/worksheets/f_Functions/currying_9_all.sc

Lines changed: 0 additions & 72 deletions
This file was deleted.

src/main/worksheets/f_Functions/currying_1_intro.sc renamed to src/main/worksheets/f_Functions/d_currying_1_intro.sc

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ def acceptString(s: String, pred: String => Boolean): Boolean = pred(s)
1414
acceptString("Hello World", seq => seq.length > 1)
1515
acceptString("Hello World", seq => seq.length < 100)
1616

17+
/**
18+
* Enables definition of functions which look more like built-in language constructs
19+
*/
1720
def acceptStringCurried(s: String)(pred: String => Boolean): Boolean = pred(s)
1821

1922
acceptStringCurried("Hello World") {
@@ -22,4 +25,5 @@ acceptStringCurried("Hello World") {
2225

2326
acceptStringCurried("Hello World") {
2427
seq => seq.length < 100
25-
}
28+
}
29+
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/**
2+
* Curried functions enable compiler for type inference
3+
*/
4+
def acceptCurried[T](something: T)(pred: T => Boolean): Boolean = pred(something)
5+
6+
7+
// types in predicate function can be omitted
8+
acceptCurried("Curry")(s => s.length > 0)
9+
acceptCurried("Curry")(_.length > 0)
10+
acceptCurried(15)(i => i > 0)
11+
acceptCurried(15)(_ > 0)
12+
13+
14+
// Type inference is not possible in uncurried version
15+
def accept[T](s: T, pred: T => Boolean): Boolean = pred(s)
16+
17+
accept("Curry", (s: String) => s.length > 0)
18+
accept(15, (i: Int) => i > 0)
19+
20+
// without currying this is not possible:
21+
//accept("Curry", s => s.length > 0)
22+
//accept("Curry", _.length > 0)
23+
//accept(15)(i => i > 0)
24+
//accept(15)(_ > 0)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/**
2+
* Currying must be used when working with implicit parameter lists.
3+
*
4+
* Implicit parameter lists are frequently used to inject dependencies into functions.
5+
*/
6+
def accept(s: String)(implicit pred: String => Boolean): Boolean = pred(s)
7+
8+
implicit val isOink: String => Boolean = s => s == "Oink"
9+
10+
accept("Yeeha")
11+
accept("Oink")
12+
13+
// Show Example code from Play framework project with implicit request

src/main/worksheets/f_Functions/currying_2_loan_pattern.sc renamed to src/main/worksheets/f_Functions/d_currying_99_bonus_loan_pattern.sc

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,12 @@ import java.util.Scanner
33

44
import scala.util.Try
55

6-
// loan pattern - loan a resource to a function
6+
7+
/**
8+
* Loan pattern: Loan a resource to a function
9+
*
10+
* Here without currying
11+
*/
712
def withFile[T](f: File, handler: Scanner => T): Option[T] = {
813
val scanner = Try(new Scanner(f))
914
try {
@@ -18,5 +23,5 @@ def withFile[T](f: File, handler: Scanner => T): Option[T] = {
1823
}
1924
}
2025

21-
withFile(new File("idea.properties"), scanner =>
26+
val properties = withFile(new File("idea.properties"), scanner =>
2227
scanner.useDelimiter("\\Z").next())

src/main/worksheets/f_Functions/currying_3_loan_pattern_curried.sc renamed to src/main/worksheets/f_Functions/d_currying_99_bonus_loan_pattern_curried.sc

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,12 @@ import scala.util.Try
77
// or a by name parameter. This has two advantages. First, the function argument
88
// can then look like a code block enclosed in braces. E.g.
99

10-
11-
def withFileCurried[T](f: File)(handler: Scanner => T): Option[T] = {
10+
/**
11+
* Loan pattern: Loan a resource to a function
12+
*
13+
* Here with currying
14+
*/
15+
def withFile[T](f: File)(handler: Scanner => T): Option[T] = {
1216
val scanner = Try(new Scanner(f))
1317
try {
1418
scanner.map(scanner =>
@@ -22,7 +26,6 @@ def withFileCurried[T](f: File)(handler: Scanner => T): Option[T] = {
2226
}
2327
}
2428

25-
// curried version of a function looks like built in control structure
26-
withFileCurried(new File("idea.properties")) { scanner =>
29+
val properties = withFile(new File("idea.properties")) { scanner =>
2730
scanner.useDelimiter("\\Z").next()
2831
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/**
2+
* "Currying is the technique of translating the evaluation of a function that takes
3+
* multiple arguments (or a tuple of arguments) into evaluating a sequence of functions,
4+
* each with a single argument (partial application)"
5+
*
6+
* https://en.wikipedia.org/wiki/Currying
7+
*/
8+
9+
def sum(x: Int, y: Int) = x + y
10+
def sumCurried(x: Int)(y: Int) = x + y
11+
12+
def acceptString(s: String, pred: String => Boolean): Boolean = pred(s)
13+
14+
acceptString("Hello World", seq => seq.length > 1)
15+
acceptString("Hello World", seq => seq.length < 100)
16+
17+
/**
18+
* Enables definition of functions which look more like built-in language constructs
19+
*/
20+
def acceptStringCurried(s: String)(pred: String => Boolean): Boolean = pred(s)
21+
22+
acceptStringCurried("Hello World") {
23+
seq => seq.length > 1
24+
}
25+
26+
acceptStringCurried("Hello World") {
27+
seq => seq.length < 100
28+
}
29+
30+
/**
31+
* Curried functions enable compiler for type inference
32+
*/
33+
def acceptCurried[T](something: T)(pred: T => Boolean): Boolean = pred(something)
34+
35+
36+
// types in predicate function can be omitted
37+
acceptCurried("Curry")(s => s.length > 0)
38+
acceptCurried("Curry")(_.length > 0)
39+
acceptCurried(15)(i => i > 0)
40+
acceptCurried(15)(_ > 0)
41+
42+
43+
// Type inference is not possible in uncurried version
44+
def accept[T](s: T, pred: T => Boolean): Boolean = pred(s)
45+
46+
accept("Curry", (s: String) => s.length > 0)
47+
accept(15, (i: Int) => i > 0)
48+
49+
// without currying this is not possible:
50+
//accept("Curry", s => s.length > 0)
51+
//accept("Curry", _.length > 0)
52+
//accept(15)(i => i > 0)
53+
//accept(15)(_ > 0)
54+
55+
/**
56+
* Currying must be used when working with implicit parameter lists.
57+
*
58+
* Implicit parameter lists are frequently used to inject dependencies into functions.
59+
*/
60+
def accept(s: String)(implicit pred: String => Boolean): Boolean = pred(s)
61+
62+
implicit val isOink: String => Boolean = s => s == "Oink"
63+
64+
accept("Yeeha")
65+
accept("Oink")
66+
67+
// Show Example code from Play framework project with implicit request

src/main/worksheets/f_Functions/xxx_a_different_shapes_3_syntactic_sugar.sc

Lines changed: 0 additions & 13 deletions
This file was deleted.

0 commit comments

Comments
 (0)