I don't understand why authors said that Code Listing 9.1 from "Programming in Scala" use closure. In chapter 9, they show how to refactor code into more less duplicated form, from this original code:
object FileMatcher {
private def filesHere = (new java.io.File(".")).listFiles
def filesEnding(query: String) =
for (file <- filesHere; if file.getName.endsWith(query))
yield file
def filesContaining(query: String) =
for (file <- filesHere; if file.getName.contains(query))
yield file
def filesRegex(query: String) =
for (file <- filesHere; if file.getName.matches(query))
yield file
}
To the second version:
object FileMatcher {
private def filesHere = (new java.io.File(".")).listFiles
def filesMatching(query: String,
matcher: (String, String) => Boolean) = {
for (file <- filesHere; if matcher(file.getName, query))
yield file
}
def filesEnding(query: String) =
filesMatching(query, _.endsWith(_))
def filesContaining(query: String) =
filesMatching(query, _.contains(_))
def filesRegex(query: String) =
filesMatching(query, _.matches(_))
}
Which they said that there is no use of closure here. Now I understand until this point. However they introduced the use of closure to refactor even some more, shown in Listing 9.1:
object FileMatcher {
private def filesHere = (new java.io.File(".")).listFiles
private def filesMatching(matcher: String => Boolean) =
for (file <- filesHere; if matcher(file.getName))
yield file
def filesEnding(query: String) =
filesMatching(_.endsWith(query))
def filesContaining(query: String) =
filesMatching(_.contains(query))
def filesRegex(query: String) =
filesMatching(_.matches(query))
}
Now they said that query is a free variable but I don't really understand why they said so? Since ""query"" seems to be passed from top method down to string matching function explicitly.
Let's look at the classic add-n closure from What is a closure.
(define (add a)
(lambda (b)
(+ a b)))
(define add3 (add 3))
(add3 4) returns 7
In the above lambda expression, a
is the free variable, which is defined in the Wikipedia link to be:
a variable referred to in a function that is not a local variable or an argument of that function. An upvalue is a free variable that has been bound (closed over) with a closure.
Coming back to
def filesEnding(query: String) =
filesMatching(_.endsWith(query))
The implicit function x => x.endsWith(query)
is the first-class function, which is assigned to first-class value matcher
, and _.endsWith()
is closed over query
, similar to the way 3 closes up a
in (add 3)
. (add3 4)
equivalent is done by matcher(file.getName)
.
Edit: Tricky part is the feature in Scala called placeholder syntax anonymous functions. By using _
in place of the sender or the parameter, Scala automatically creates an anonymous function, which we can consider it as lambda expression.
For example,
_ + 1 creates x => x + 1
_ * _ creates (x1, x2) => x1 * x2
_.endsWith(query) creates x => x.endsWith(query)
Within the function x => x.endsWith(query)
, query
meets the two requirements of being a free variable:
query
is not a local variable defined within the function (there is no local variable).query
is not an argument of the function (the only argument is x
).If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With