Reduce code duplication in Scala

Source: Internet
Author: User

All functions are split into common parts, which are identical in each function call, and are not common parts that may change in different function calls. The common part is the function body, and not the generic part must be supplied by the parameter. When you use a function value as a parameter, the generic part of the algorithm is some other algorithm that it represents. In each invocation of this function, you can pass different function values as arguments, and the called function will call the Passed-in function value each time the parameter is selected. This higher-order function: Higher-order function--functions that take other functions as arguments-gives you an extra chance to organize and simplify the code.

One advantage of higher-order functions is that they allow you to create control abstractions that allow you to reduce code duplication. For example, suppose you are writing a file browser, and you want to provide an API that allows users to search for files that match certain criteria. First, you add the mechanism for the search file name to end with a specific string. This allows your users to discover, for example, all files with the extension ". Scala". You can provide such an API by defining the exposed Filesending method in a single instance object, such as:

object FileMatcher {
  private def filesHere = (new java.io.File(".")).listFiles
  def filesEnding(query: String) =
   for (file < - filesHere; if file.getName.endsWith(query))
    yield file
}

The Filesending method Fileshere accept the list of all files in the current directory by using the private Help method, and then filters them based on whether each file name ends with a user-specific query. Since Fileshere is private, the filesending approach is to define the only accessible method in the api,filesmatcher you provide to your users.

So far it's good, no duplicate code. Later, however, you decided to make the query available based on any part of the file name. This feature can be used well in the following situations: Your users cannot remember that they are naming files in PHB-IMPORTANT.DOC,STUPID-PUB-REPORT.DOC,MAY2003SALESDOC.PHB, or whatever names are completely different, but they think " The PHB "appears somewhere in the file. You go back to work and add this function to your api,filematcher:

def filesContaining(query: String) =
  for (file < - filesHere; if file.getName.contains(query))
   yield file

This function is similar to filesending. It searches for Fileshere, checks the name, and returns the file if the name matches. The only difference is that this function uses contains instead of endswith.

As time goes on, the program becomes more successful. Finally, you succumb to the needs of several powerful users who want to search based on regular expressions. These sloppy guys have a huge catalog of thousands of files, and they want to do things like Find all the "PDF" files that contain "Oopsla" in the title. To support them, you wrote this function:

def filesRegex(query: String) =
  for (file < - filesHere; if file.getName.matches(query))
   yield file

Experienced programmers will notice all of these repetitions and wonder if they can extract common help functions from them. However, the obvious way does not work. What you would like to do is this:

def filesMatching(query: String, method) =
  for (file < - filesHere; if file.getName.method(query))
   yield file

This approach works in some dynamic languages, but Scala does not allow code to be bonded at runtime. So what should you do?

The function value provides an answer. Although you cannot pass the method name as a value, you can achieve the same effect by passing the value of the function that invokes the method. In this example, you can add a Matcher parameter to the method whose sole purpose is to check the file name for the query:

def filesMatching(query: String,
   matcher: (String, String) => Boolean) = {
  for (file < - filesHere; if matcher(file.getName, query))
   yield file
}

In this version of the method, the IF clause now uses Matcher to check the file name for the query. More precisely, this check does not depend on what the Matcher defines. Now look at the type of matcher. It is a function, so there is a => in the type. This function takes two string arguments--file name and query--and returns a Boolean value, so the type of this function is (string, String) => Boolean.

With this new filesmatching help method, you can simplify them by having three search methods call it and pass in the appropriate function:

def filesEnding(query: String) =
  filesMatching(query, _.endsWith(_))
def filesContaining(query: String) =
  filesMatching(query, _.contains(_))
def filesRegex(query: String) =
  filesMatching(query, _.matches(_))

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.