An overview of functional programming

In today’s major programming languages, the functional programming paradigm is more or less “standard,” or the major languages are all functional extensions, which is a big trend. In Java, for example, with higher-order functions such as Lambda blocks and the Stream API, Java is finally equipped with functional tools. Extensive C++ has also added support for Lambda blocks in the 2011 version of the language standard; Another example is Groovy, which I’ve been experimenting with for a while now. Although it runs on the JVM, its use of dynamic languages, functional programming paradigms, and meta-programming capabilities offers expressiveness and simplicity that beats Java by a few blocks. You can leverage all of Groovy’s dynamic capabilities to build high-performance JVM applications that increase development efficiency by orders of magnitude. There are many examples of languages, and I will not enumerate them all.

Note: This article was published on My public account CodeSheep. You can subscribe by holding down or scanning the heart below ↓ ↓ ↓



Why use the functional programming paradigm

So here are a couple of typical features of functional programming, the object of distinction is traditional imperative programming

  • 0x01. Higher Level of abstraction (Higher order functions)

Replacing basic control structures with higher-level abstractions is a whole new way of thinking in itself, allowing developers to focus on business scenarios without bothering with complex layers

For example, we use the Java language to capitalize all the words in a collection of strings

If we follow the traditional imperative programming approach, then it is no surprise that we have to write loops and iterate over such iterations:

for (int i=0; i<wordList.size(); i++) {
   wordList.get(i).toUpperCase();
}
Copy the code

But if you use Java’s functional programming paradigm, everything is elegant, in one sentence

wordList.stream.map( w -> w.toUpperCase() )
Copy the code

The map() function here is what is called a higher-order function. We use higher-order functions instead of low-level iterations because we don’t deal with the details, we just define the mapping logic, and the iterations are done automatically by higher-order functions!

  • 0x02. Improved code SNR (Simplicity)

Unlike object-oriented languages, which encapsulate uncertainty with abstractions, functional programming makes code extremely concise by minimizing uncertainty

I don’t think I need to say more about the advantages of the above example

  • 0x03. Transfer of control to runtime (dynamic)

Unlike traditional compiled languages, dynamic languages with functional programming paradigms transfer more control to the language runtime for greater flexibility, expressiveness, and performance trade-offs.

These three advantages will be truly felt and understood in the following examples!



Example analysis of functional programming

Example 1: Word frequency statistics

What it does is simple: Given a set of words, count the number of words in the set other than particles (of, on, the, etc.), case insensitive

Imperative solution: At least in the following steps

  • Start with a loop iteration
  • Then all the words are lowercase
  • Then determine whether the word is a particle
  • Finally, word frequency statistics are carried out
public class WordCount {

    // Define a set of auxiliary words that are not counted
    private Set<String> auxiliaryWordSet = new HashSet<String>() {{
       add("of"); add("the"); add("to"); add("and"); add("so"); add("are");
    }};

    // Traditional imperative solution to implement the word frequency statistics function
    public Map doWordCount( List<String> context ) {
        Map<String,Integer> result = new HashMap<String, Integer>();
        for ( String word:context ) {  // loop iteration
            String lowerCaseWord = word.toLowerCase();  // Convert all words to lowercase
            if( !auxiliaryWordSet.contains(lowerCaseWord) ) {
                if( null == result.get(lowerCaseWord) )
                    result.put( lowerCaseWord, 1 );
                else
                    result.put( lowerCaseWord, result.get(lowerCaseWord)+1); }}return result;
    }

    / / the main () function
    public static void main(String[] args) {
        List<String> wordList = new ArrayList<String>() {{
            add("The"); add("Products"); add("of"); add("Samsung"); add("and"); add("Apple");
            add("are"); add("so"); add("amazing"); add("especially"); add("Apple");
        }};

        WordCount wordCount = new WordCount();
        Map res = wordCount.doWordCount( wordList );
        System.out.print(res); // print: {apple=2, amazing=1, Samsung =1, especially=1, products=1}}}Copy the code

Functional solution:

If we were to rewrite the doWordCount() function using Java’s Stream API and the functional paradigm of Lambda blocks, everything would be so neat:

public Map doWordCount2( List<String> context ) { Map<String,Integer> result = new HashMap<String, Integer>(); context.stream().map( w -> w.toLowerCase() ) .filter( w -> ! auxiliaryWordSet.contains(w) ) .forEach( w -> result.put( w, result.getOrDefault(w,0) + 1 ) );return result;
}
Copy the code

Note: getOrDefault is a Java Map convenience function that returns a “default” value if a given key is not found in the Map.

Compared to the imperative solution, the user saves a lot of tedious iteration and judgment, we only focus on the business logic, the code SNR is greatly improved!


Example 2: Join words into sentences

Given a discrete set of words, we want to capitalize the first letter of words with more than one letter and use a dash – to connect them into a sentence

Imperative solution:

public class WordConnect {

    // Capitalize the first letter of words
    public String capitalizeFirstLetter( String s ) {
        return s.substring(0.1).toUpperCase() + s.substring(1,s.length() );
    }

    // Join words into sentences
    public String connectWord( List<String> context ) {
        StringBuilder result = new StringBuilder();
        for ( String word: context ) {
            if ( word.length() > 1 ) {
                result.append( capitalizeFirstLetter(word) );
                result.append("-"); }}return result.substring(0,result.length()-1).toString();
    }

    / / the main () function
    public static void main(String[] args) {
        List<String> wordList = new ArrayList<String>() {{
            add("The"); add("Products"); add("of"); add("Samsung"); add("and"); add("Apple");
            add("are"); add("so"); add("amazing"); add("especially"); add("Apple");
        }};

        WordConnect wordConnect = new WordConnect();
        String res = wordConnect.connectWord( wordList );
        System.out.print(res); // Print: The -products-of-samsung -And- apple-are-so-amazing -Especially-Apple}}Copy the code

Functional solution 1: Java Steam API and Lambda block implementation

public String connectWord( List<String> context ) {
    return context.stream().filter( w -> w.length()>1 )
            .map( w -> capitalizeFirstLetter(w) )
            .collect( Collectors.joining("-")); }Copy the code

I don’t want to say anything, this is not too concise okay!

Functional solution 2: Groovy language implementation

public String connectWord( context ) {
    context.findAll { it.length() >1 }
    .collect { it.capitalize() }
    .join The '-'
}
Copy the code

For a first taste of the Groovy language, see my article: First Taste of Groovy: Building High-performance JVM Applications



Functional best practice: Write a triple quote book efficiently

I still remember last year’s 520, in order to express my infinite and inexpressible love for my wife, I wanted to write a code love letter of no more than three lines. I wanted to express as much as possible in as short a code as possible, so I chose functional programming.

My 520 three-line code love letter is here:

public TimeRiver timeFlow( List<DaysMeetYou> days ) {
    return (TimeRiver)days.stream()
        .filter( n->theDaysNotWithYou(n) )
        .map( e->accompanyByMyLove(e) )
        .collect( Collectors.joining("❤ ️")); }Copy the code



Afterword.

First experience with Groovy: Building high-performance JVM applications

If you are interested, check out some of the author’s articles on containerization and microservitization:

  • RPC framework practice: Apache Thrift
  • Establishment of microservice call chain tracking center
  • Use K8S technology stack to create personal private cloud serial articles
  • Docker container visual monitoring center was built
  • Use ELK to build Docker containerized application log center
  • Spring Boot application monitoring actual combat

More original articles by author: here