Functional Programming Face-Off: Python vs JavaScript vs Go!

Functional programming has been gaining popularity in recent years, and for good reason. It offers a number of benefits over traditional imperative programming, such as improved code readability, testability, and maintainability.

In this article, we’ll compare and contrast how three popular programming languages – Python, JavaScript, and Go – handle functional programming concepts. We’ll explore how each language supports features like higher-order functions, immutability, and function composition, and discuss their strengths and weaknesses.

If you’d rather watch than read:

Check out the accompanying YouTube video!

1. Defining and Calling Functions

At the heart of functional programming lies, unsurprisingly, the function. The way functions are defined and invoked can significantly impact a language’s suitability for functional programming paradigms. We’ll examine how Python, JavaScript, and Go handle function definitions, looking at syntax, typing, and overall structure, setting the stage for more advanced functional concepts. Specifically how similar (or different) the syntax is, and the implications of different approaches to type systems (static, dynamic, type hints).

Python

<span>def</span> <span>square</span><span>(</span><span>i</span><span>:</span> <span>int</span><span>)</span> <span>-></span> <span>int</span><span>:</span>
<span>return</span> <span>i</span> <span>*</span> <span>i</span>
<span>result</span> <span>=</span> <span>square</span><span>(</span><span>5</span><span>)</span>
<span>print</span><span>(</span><span>result</span><span>)</span>
<span>def</span> <span>square</span><span>(</span><span>i</span><span>:</span> <span>int</span><span>)</span> <span>-></span> <span>int</span><span>:</span>
    <span>return</span> <span>i</span> <span>*</span> <span>i</span>

<span>result</span> <span>=</span> <span>square</span><span>(</span><span>5</span><span>)</span>
<span>print</span><span>(</span><span>result</span><span>)</span>
def square(i: int) -> int: return i * i result = square(5) print(result)

Enter fullscreen mode Exit fullscreen mode

In Python, functions are defined using the def keyword followed by the function name, parentheses for parameters, and a colon. The code block within the function is indented. Type hints can be optionally added to specify the expected types of parameters and return values.

JavaScript

<span>const</span> <span>square</span> <span>=</span> <span>i</span> <span>=></span> <span>i</span> <span>*</span> <span>i</span><span>;</span>
<span>const</span> <span>result</span> <span>=</span> <span>square</span><span>(</span><span>5</span><span>);</span>
<span>console</span><span>.</span><span>log</span><span>(</span><span>result</span><span>);</span>
<span>const</span> <span>square</span> <span>=</span> <span>i</span> <span>=></span> <span>i</span> <span>*</span> <span>i</span><span>;</span>

<span>const</span> <span>result</span> <span>=</span> <span>square</span><span>(</span><span>5</span><span>);</span>
<span>console</span><span>.</span><span>log</span><span>(</span><span>result</span><span>);</span>
const square = i => i * i; const result = square(5); console.log(result);

Enter fullscreen mode Exit fullscreen mode

JavaScript offers a more compact syntax for defining functions, particularly with arrow functions. Arrow functions use the => operator, providing a concise way to express a function’s logic.

Go

<span>package</span> <span>main</span>
<span>import</span> <span>(</span>
<span>"fmt"</span>
<span>)</span>
<span>func</span> <span>square</span><span>(</span><span>i</span> <span>int</span><span>)</span> <span>int</span> <span>{</span>
<span>return</span> <span>i</span> <span>*</span> <span>i</span>
<span>}</span>
<span>func</span> <span>main</span><span>()</span> <span>{</span>
<span>result</span> <span>:=</span> <span>square</span><span>(</span><span>5</span><span>)</span>
<span>fmt</span><span>.</span><span>Println</span><span>(</span><span>result</span><span>)</span>
<span>}</span>
<span>package</span> <span>main</span>

<span>import</span> <span>(</span>
    <span>"fmt"</span>
<span>)</span>

<span>func</span> <span>square</span><span>(</span><span>i</span> <span>int</span><span>)</span> <span>int</span> <span>{</span>
    <span>return</span> <span>i</span> <span>*</span> <span>i</span>
<span>}</span>

<span>func</span> <span>main</span><span>()</span> <span>{</span>
    <span>result</span> <span>:=</span> <span>square</span><span>(</span><span>5</span><span>)</span>
    <span>fmt</span><span>.</span><span>Println</span><span>(</span><span>result</span><span>)</span>
<span>}</span>
package main import ( "fmt" ) func square(i int) int { return i * i } func main() { result := square(5) fmt.Println(result) }

Enter fullscreen mode Exit fullscreen mode

Go, a statically-typed language, requires explicit type declarations for both function parameters and return values. Functions are defined using the func keyword, followed by the function name, a parenthesized list of parameters (with their types), and the return type. The function body is enclosed in curly braces {}. Go’s syntax is very similar to python in that it uses a keyword, followed by the name, followed by parameters. However, Go’s strict typing and the need for explicit imports, even for basic operations like printing to the console (using the fmt package), introduce a slightly higher level of formality compared to Python and JavaScript. The Go example defines a function that, like the Python and JavaScript counterparts, takes an integer and returns its square.

However, Go differs significantly in its overall structure. Every Go file belongs to a package, and the package main declaration is special. It signifies that the file is part of the main package, which is the entry point for executable programs. Without package main and the func main() within it, Go wouldn’t know where to begin executing your code. It’s a fundamental difference from Python and JavaScript, where you don’t need such explicit entry point declarations for simple scripts. Another key distinction is Go’s requirement for explicit imports, even for basic functionalities like printing to the console. In the provided example, fmt.Println is used, requiring an import of the fmt (format) package.

2. Higher-Order Functions

This section delves into a cornerstone of functional programming: treating functions as first-class citizens. This means functions can be passed as arguments to other functions, returned as values from functions, and generally treated like any other variable. A direct consequence of this is the ability to create higher-order functions – functions that either take other functions as arguments or return them (or both). This allows for highly flexible and reusable code. We will also be touching on Closures, though the dedicated section for them comes later.

Python

<span>def</span> <span>applyOperation</span><span>(</span><span>operation</span><span>,</span> <span>a</span><span>:</span> <span>int</span><span>,</span> <span>b</span><span>:</span> <span>int</span><span>)</span> <span>-></span> <span>int</span><span>:</span>
<span>return</span> <span>operation</span><span>(</span><span>a</span><span>,</span> <span>b</span><span>)</span>
<span>def</span> <span>add</span><span>(</span><span>a</span><span>:</span> <span>int</span><span>,</span> <span>b</span><span>:</span> <span>int</span><span>)</span> <span>-></span> <span>int</span><span>:</span>
<span>return</span> <span>a</span> <span>+</span> <span>b</span>
<span>def</span> <span>subtract</span><span>(</span><span>a</span><span>:</span> <span>int</span><span>,</span> <span>b</span><span>:</span> <span>int</span><span>)</span> <span>-></span> <span>int</span><span>:</span>
<span>return</span> <span>a</span> <span>-</span> <span>b</span>
<span>result</span> <span>=</span> <span>applyOperation</span><span>(</span><span>add</span><span>,</span> <span>10</span><span>,</span> <span>5</span><span>)</span>
<span>print</span><span>(</span><span>result</span><span>)</span> <span># Output: 15 </span>
<span>result</span> <span>=</span> <span>applyOperation</span><span>(</span><span>subtract</span><span>,</span> <span>10</span><span>,</span> <span>5</span><span>)</span>
<span>print</span><span>(</span><span>result</span><span>)</span> <span># Output: 5 </span>
<span>def</span> <span>applyOperation</span><span>(</span><span>operation</span><span>,</span> <span>a</span><span>:</span> <span>int</span><span>,</span> <span>b</span><span>:</span> <span>int</span><span>)</span> <span>-></span> <span>int</span><span>:</span>
    <span>return</span> <span>operation</span><span>(</span><span>a</span><span>,</span> <span>b</span><span>)</span>


<span>def</span> <span>add</span><span>(</span><span>a</span><span>:</span> <span>int</span><span>,</span> <span>b</span><span>:</span> <span>int</span><span>)</span> <span>-></span> <span>int</span><span>:</span>
    <span>return</span> <span>a</span> <span>+</span> <span>b</span>


<span>def</span> <span>subtract</span><span>(</span><span>a</span><span>:</span> <span>int</span><span>,</span> <span>b</span><span>:</span> <span>int</span><span>)</span> <span>-></span> <span>int</span><span>:</span>
    <span>return</span> <span>a</span> <span>-</span> <span>b</span>


<span>result</span> <span>=</span> <span>applyOperation</span><span>(</span><span>add</span><span>,</span> <span>10</span><span>,</span> <span>5</span><span>)</span>
<span>print</span><span>(</span><span>result</span><span>)</span>  <span># Output: 15 </span>
<span>result</span> <span>=</span> <span>applyOperation</span><span>(</span><span>subtract</span><span>,</span> <span>10</span><span>,</span> <span>5</span><span>)</span>
<span>print</span><span>(</span><span>result</span><span>)</span>  <span># Output: 5 </span>
def applyOperation(operation, a: int, b: int) -> int: return operation(a, b) def add(a: int, b: int) -> int: return a + b def subtract(a: int, b: int) -> int: return a - b result = applyOperation(add, 10, 5) print(result) # Output: 15 result = applyOperation(subtract, 10, 5) print(result) # Output: 5

Enter fullscreen mode Exit fullscreen mode

Python supports higher-order functions elegantly. In the Python snippet, applyOperation is a higher-order function because it takes another function (operation) as an argument. add and subtract are regular functions that perform addition and subtraction, respectively. applyOperation then calls the passed-in function (operation) with the provided arguments (a and b). Notice that the type hints are optional in Python. While the example does use type hints for clarity (specifying that operation should be a function taking two integers and returning an integer, and that a and b are integers), they are not enforced at runtime by default. This makes the Python code concise and similar in that aspect to JavaScript.

JavaScript

<span>function</span> <span>applyOperation</span><span>(</span><span>operation</span><span>,</span> <span>a</span><span>,</span> <span>b</span><span>)</span> <span>{</span>
<span>return</span> <span>operation</span><span>(</span><span>a</span><span>,</span> <span>b</span><span>);</span>
<span>}</span>
<span>function</span> <span>add</span><span>(</span><span>a</span><span>,</span> <span>b</span><span>)</span> <span>{</span>
<span>return</span> <span>a</span> <span>+</span> <span>b</span><span>;</span>
<span>}</span>
<span>function</span> <span>subtract</span><span>(</span><span>a</span><span>,</span> <span>b</span><span>)</span> <span>{</span>
<span>return</span> <span>a</span> <span>-</span> <span>b</span><span>;</span>
<span>}</span>
<span>let</span> <span>result</span> <span>=</span> <span>applyOperation</span><span>(</span><span>add</span><span>,</span> <span>10</span><span>,</span> <span>5</span><span>);</span>
<span>console</span><span>.</span><span>log</span><span>(</span><span>result</span><span>);</span> <span>// Output: 15</span>
<span>result</span> <span>=</span> <span>applyOperation</span><span>(</span><span>subtract</span><span>,</span> <span>10</span><span>,</span> <span>5</span><span>);</span>
<span>console</span><span>.</span><span>log</span><span>(</span><span>result</span><span>);</span> <span>// Output: 5</span>
<span>function</span> <span>applyOperation</span><span>(</span><span>operation</span><span>,</span> <span>a</span><span>,</span> <span>b</span><span>)</span> <span>{</span>
  <span>return</span> <span>operation</span><span>(</span><span>a</span><span>,</span> <span>b</span><span>);</span>
<span>}</span>

<span>function</span> <span>add</span><span>(</span><span>a</span><span>,</span> <span>b</span><span>)</span> <span>{</span>
  <span>return</span> <span>a</span> <span>+</span> <span>b</span><span>;</span>
<span>}</span>

<span>function</span> <span>subtract</span><span>(</span><span>a</span><span>,</span> <span>b</span><span>)</span> <span>{</span>
  <span>return</span> <span>a</span> <span>-</span> <span>b</span><span>;</span>
<span>}</span>

<span>let</span> <span>result</span> <span>=</span> <span>applyOperation</span><span>(</span><span>add</span><span>,</span> <span>10</span><span>,</span> <span>5</span><span>);</span>
<span>console</span><span>.</span><span>log</span><span>(</span><span>result</span><span>);</span> <span>// Output: 15</span>

<span>result</span> <span>=</span> <span>applyOperation</span><span>(</span><span>subtract</span><span>,</span> <span>10</span><span>,</span> <span>5</span><span>);</span>
<span>console</span><span>.</span><span>log</span><span>(</span><span>result</span><span>);</span> <span>// Output: 5</span>
function applyOperation(operation, a, b) { return operation(a, b); } function add(a, b) { return a + b; } function subtract(a, b) { return a - b; } let result = applyOperation(add, 10, 5); console.log(result); // Output: 15 result = applyOperation(subtract, 10, 5); console.log(result); // Output: 5

Enter fullscreen mode Exit fullscreen mode

JavaScript, like Python, treats functions as first-class citizens and readily supports higher-order functions. The JavaScript snippet demonstrates the same applyOperation, add, and subtract structure as the Python example. applyOperation accepts a function (operation) and calls it with arguments a and b. Because JavaScript is dynamically typed, there are no type annotations. The code is very concise and mirrors the Python example in its functional approach.

Go

<span>package</span> <span>main</span>
<span>import</span> <span>"fmt"</span>
<span>func</span> <span>applyOperation</span><span>(</span><span>operation</span> <span>func</span><span>(</span><span>int</span><span>,</span> <span>int</span><span>)</span> <span>int</span><span>,</span> <span>a</span> <span>int</span><span>,</span> <span>b</span> <span>int</span><span>)</span> <span>int</span> <span>{</span>
<span>return</span> <span>operation</span><span>(</span><span>a</span><span>,</span> <span>b</span><span>)</span>
<span>}</span>
<span>func</span> <span>add</span><span>(</span><span>a</span><span>,</span> <span>b</span> <span>int</span><span>)</span> <span>int</span> <span>{</span>
<span>return</span> <span>a</span> <span>+</span> <span>b</span>
<span>}</span>
<span>func</span> <span>subtract</span><span>(</span><span>a</span><span>,</span> <span>b</span> <span>int</span><span>)</span> <span>int</span> <span>{</span>
<span>return</span> <span>a</span> <span>-</span> <span>b</span>
<span>}</span>
<span>func</span> <span>main</span><span>()</span> <span>{</span>
<span>result</span> <span>:=</span> <span>applyOperation</span><span>(</span><span>add</span><span>,</span> <span>10</span><span>,</span> <span>5</span><span>)</span>
<span>fmt</span><span>.</span><span>Println</span><span>(</span><span>result</span><span>)</span> <span>// Output: 15</span>
<span>result</span> <span>=</span> <span>applyOperation</span><span>(</span><span>subtract</span><span>,</span> <span>10</span><span>,</span> <span>5</span><span>)</span>
<span>fmt</span><span>.</span><span>Println</span><span>(</span><span>result</span><span>)</span> <span>// Output: 5</span>
<span>}</span>
<span>package</span> <span>main</span>

<span>import</span> <span>"fmt"</span>

<span>func</span> <span>applyOperation</span><span>(</span><span>operation</span> <span>func</span><span>(</span><span>int</span><span>,</span> <span>int</span><span>)</span> <span>int</span><span>,</span> <span>a</span> <span>int</span><span>,</span> <span>b</span> <span>int</span><span>)</span> <span>int</span> <span>{</span>
    <span>return</span> <span>operation</span><span>(</span><span>a</span><span>,</span> <span>b</span><span>)</span>
<span>}</span>

<span>func</span> <span>add</span><span>(</span><span>a</span><span>,</span> <span>b</span> <span>int</span><span>)</span> <span>int</span> <span>{</span>
    <span>return</span> <span>a</span> <span>+</span> <span>b</span>
<span>}</span>

<span>func</span> <span>subtract</span><span>(</span><span>a</span><span>,</span> <span>b</span> <span>int</span><span>)</span> <span>int</span> <span>{</span>
    <span>return</span> <span>a</span> <span>-</span> <span>b</span>
<span>}</span>

<span>func</span> <span>main</span><span>()</span> <span>{</span>
    <span>result</span> <span>:=</span> <span>applyOperation</span><span>(</span><span>add</span><span>,</span> <span>10</span><span>,</span> <span>5</span><span>)</span>
    <span>fmt</span><span>.</span><span>Println</span><span>(</span><span>result</span><span>)</span> <span>// Output: 15</span>

    <span>result</span> <span>=</span> <span>applyOperation</span><span>(</span><span>subtract</span><span>,</span> <span>10</span><span>,</span> <span>5</span><span>)</span>
    <span>fmt</span><span>.</span><span>Println</span><span>(</span><span>result</span><span>)</span> <span>// Output: 5</span>
<span>}</span>
package main import "fmt" func applyOperation(operation func(int, int) int, a int, b int) int { return operation(a, b) } func add(a, b int) int { return a + b } func subtract(a, b int) int { return a - b } func main() { result := applyOperation(add, 10, 5) fmt.Println(result) // Output: 15 result = applyOperation(subtract, 10, 5) fmt.Println(result) // Output: 5 }

Enter fullscreen mode Exit fullscreen mode

Go also supports higher-order functions, although with its characteristic explicitness due to static typing. In the Go snippet, applyOperation is again the higher-order function. However, the type of the operation parameter is explicitly declared: func(int, int) int. This signifies that operation must be a function that takes two int arguments and returns an int. This explicit type declaration is a key difference from Python (with optional type hints) and JavaScript (dynamically typed). The add and subtract functions are defined with their types, and applyOperation calls the provided function just like in the other languages. While all three languages achieve the same result, Go’s static typing makes the function signatures more verbose. This reinforces Go’s emphasis on explicitness and compile-time type safety.

3. Closures

Closures are a powerful feature often used in conjunction with higher-order functions. A closure is a function that “remembers” its surrounding environment (its lexical scope) even after the outer function that created it has finished executing. This means the inner function can access and modify variables defined in the outer function’s scope, even if the outer function has returned. This ability to “capture” state is crucial for many functional programming patterns.

Python

<span>def</span> <span>createCounter</span><span>():</span>
<span>count</span> <span>=</span> <span>0</span>
<span>def</span> <span>counter</span><span>():</span>
<span>nonlocal</span> <span>count</span> <span># count is not a local variable, </span> <span># it refers to the count variable in the outer scope </span> <span>count</span> <span>+=</span> <span>1</span>
<span>return</span> <span>count</span>
<span>return</span> <span>counter</span>
<span>counter</span> <span>=</span> <span>createCounter</span><span>()</span>
<span>print</span><span>(</span><span>counter</span><span>())</span>
<span>print</span><span>(</span><span>counter</span><span>())</span>
<span>def</span> <span>createCounter</span><span>():</span>
    <span>count</span> <span>=</span> <span>0</span>

    <span>def</span> <span>counter</span><span>():</span>
        <span>nonlocal</span> <span>count</span>  <span># count is not a local variable, </span>        <span># it refers to the count variable in the outer scope </span>        <span>count</span> <span>+=</span> <span>1</span>
        <span>return</span> <span>count</span>

    <span>return</span> <span>counter</span>


<span>counter</span> <span>=</span> <span>createCounter</span><span>()</span>
<span>print</span><span>(</span><span>counter</span><span>())</span>
<span>print</span><span>(</span><span>counter</span><span>())</span>
def createCounter(): count = 0 def counter(): nonlocal count # count is not a local variable, # it refers to the count variable in the outer scope count += 1 return count return counter counter = createCounter() print(counter()) print(counter())

Enter fullscreen mode Exit fullscreen mode

The Python snippet demonstrates a classic closure example with createCounter. createCounter is a function that returns another function, counter. The key here is the nonlocal count declaration within counter. Because Python has stricter scoping rules, you need to explicitly tell the inner function (counter) that count is not a local variable within counter itself, but rather refers to the count variable in the enclosing *scope of createCounter. Without nonlocal, Python would create a new, local count variable inside counter, and the outer count would remain unchanged. The returned counter function *“closes over” the count variable, maintaining its state between calls.

JavaScript

<span>const</span> <span>createCounter</span> <span>=</span> <span>()</span> <span>=></span> <span>{</span>
<span>let</span> <span>count</span> <span>=</span> <span>0</span><span>;</span>
<span>return </span><span>()</span> <span>=></span> <span>{</span>
<span>count</span><span>++</span><span>;</span>
<span>return</span> <span>count</span><span>;</span>
<span>};</span>
<span>};</span>
<span>const</span> <span>counter</span> <span>=</span> <span>createCounter</span><span>();</span>
<span>console</span><span>.</span><span>log</span><span>(</span><span>counter</span><span>());</span>
<span>console</span><span>.</span><span>log</span><span>(</span><span>counter</span><span>());</span>
<span>const</span> <span>createCounter</span> <span>=</span> <span>()</span> <span>=></span> <span>{</span>
  <span>let</span> <span>count</span> <span>=</span> <span>0</span><span>;</span>
  <span>return </span><span>()</span> <span>=></span> <span>{</span>
    <span>count</span><span>++</span><span>;</span>
    <span>return</span> <span>count</span><span>;</span>
  <span>};</span>
<span>};</span>

<span>const</span> <span>counter</span> <span>=</span> <span>createCounter</span><span>();</span>
<span>console</span><span>.</span><span>log</span><span>(</span><span>counter</span><span>());</span>
<span>console</span><span>.</span><span>log</span><span>(</span><span>counter</span><span>());</span>
const createCounter = () => { let count = 0; return () => { count++; return count; }; }; const counter = createCounter(); console.log(counter()); console.log(counter());

Enter fullscreen mode Exit fullscreen mode

JavaScript handles closures very naturally. In the JavaScript snippet, createCounter also returns an anonymous function (the closure). This inner function increments and returns the count variable. Crucially, JavaScript’s scoping rules automatically allow the inner function to access and modify the count variable from the createCounter scope, even after createCounter has completed. There’s no need for a special keyword like Python’s nonlocal; the closure behavior is implicit. This makes the JavaScript code very concise.

Go

<span>package</span> <span>main</span>
<span>import</span> <span>"fmt"</span>
<span>func</span> <span>createCounter</span><span>()</span> <span>func</span><span>()</span> <span>int</span> <span>{</span>
<span>count</span> <span>:=</span> <span>0</span>
<span>return</span> <span>func</span><span>()</span> <span>int</span> <span>{</span>
<span>count</span><span>++</span>
<span>return</span> <span>count</span>
<span>}</span>
<span>}</span>
<span>func</span> <span>main</span><span>()</span> <span>{</span>
<span>counter</span> <span>:=</span> <span>createCounter</span><span>()</span>
<span>fmt</span><span>.</span><span>Println</span><span>(</span><span>counter</span><span>())</span>
<span>fmt</span><span>.</span><span>Println</span><span>(</span><span>counter</span><span>())</span>
<span>}</span>
<span>package</span> <span>main</span>

<span>import</span> <span>"fmt"</span>

<span>func</span> <span>createCounter</span><span>()</span> <span>func</span><span>()</span> <span>int</span> <span>{</span>
    <span>count</span> <span>:=</span> <span>0</span>
    <span>return</span> <span>func</span><span>()</span> <span>int</span> <span>{</span>
            <span>count</span><span>++</span>
            <span>return</span> <span>count</span>
    <span>}</span>
<span>}</span>

<span>func</span> <span>main</span><span>()</span> <span>{</span>
    <span>counter</span> <span>:=</span> <span>createCounter</span><span>()</span>
    <span>fmt</span><span>.</span><span>Println</span><span>(</span><span>counter</span><span>())</span>
    <span>fmt</span><span>.</span><span>Println</span><span>(</span><span>counter</span><span>())</span>
<span>}</span>
package main import "fmt" func createCounter() func() int { count := 0 return func() int { count++ return count } } func main() { counter := createCounter() fmt.Println(counter()) fmt.Println(counter()) }

Enter fullscreen mode Exit fullscreen mode

Go’s closure mechanism is similar to JavaScript’s. The Go snippet defines createCounter, which returns an anonymous function that increments and returns the count variable. Like JavaScript, and unlike Python, there’s no need for any special declaration to indicate that count is from the outer scope. The inner function automatically has access to and can modify count. The returned function “closes over” the count variable, preserving its state between invocations. Go’s approach, like JavaScript’s, is straightforward and doesn’t require extra keywords for closure behavior. The syntax, returning a func() int, clearly expresses that createCounter returns a function that takes no arguments and returns an integer.

4. Partial Application

Partial application is a technique for creating new functions from existing ones by pre-filling some of their arguments. It’s a way to specialize a general function into a more specific one. Instead of calling a function with all its arguments at once, you “fix” some of the arguments, creating a new function that expects only the remaining arguments. This can lead to more reusable and readable code.

Python

<span>def</span> <span>createGreeting</span><span>(</span><span>greeting</span><span>:</span> <span>str</span><span>):</span>
<span>def</span> <span>greetingFn</span><span>(</span><span>name</span><span>:</span> <span>str</span><span>)</span> <span>-></span> <span>str</span><span>:</span>
<span>return</span> <span>f</span><span>"</span><span>{</span><span>greeting</span><span>}</span><span> </span><span>{</span><span>name</span><span>}</span><span>"</span>
<span>return</span> <span>greetingFn</span>
<span>firstGreeting</span> <span>=</span> <span>createGreeting</span><span>(</span><span>"</span><span>Well, hello there </span><span>"</span><span>)</span>
<span>secondGreeting</span> <span>=</span> <span>createGreeting</span><span>(</span><span>"</span><span>Hola </span><span>"</span><span>)</span>
<span>print</span><span>(</span><span>firstGreeting</span><span>(</span><span>"</span><span>Remi</span><span>"</span><span>))</span>
<span>print</span><span>(</span><span>secondGreeting</span><span>(</span><span>"</span><span>Ana</span><span>"</span><span>))</span>
<span>def</span> <span>createGreeting</span><span>(</span><span>greeting</span><span>:</span> <span>str</span><span>):</span>
    <span>def</span> <span>greetingFn</span><span>(</span><span>name</span><span>:</span> <span>str</span><span>)</span> <span>-></span> <span>str</span><span>:</span>
        <span>return</span> <span>f</span><span>"</span><span>{</span><span>greeting</span><span>}</span><span> </span><span>{</span><span>name</span><span>}</span><span>"</span>

    <span>return</span> <span>greetingFn</span>


<span>firstGreeting</span> <span>=</span> <span>createGreeting</span><span>(</span><span>"</span><span>Well, hello there </span><span>"</span><span>)</span>
<span>secondGreeting</span> <span>=</span> <span>createGreeting</span><span>(</span><span>"</span><span>Hola </span><span>"</span><span>)</span>
<span>print</span><span>(</span><span>firstGreeting</span><span>(</span><span>"</span><span>Remi</span><span>"</span><span>))</span>
<span>print</span><span>(</span><span>secondGreeting</span><span>(</span><span>"</span><span>Ana</span><span>"</span><span>))</span>
def createGreeting(greeting: str): def greetingFn(name: str) -> str: return f"{greeting} {name}" return greetingFn firstGreeting = createGreeting("Well, hello there ") secondGreeting = createGreeting("Hola ") print(firstGreeting("Remi")) print(secondGreeting("Ana"))

Enter fullscreen mode Exit fullscreen mode

In the Python snippet, createGreeting is a function that demonstrates partial application. It takes a greeting string as input and returns a new function (greetingFn). This returned function takes a name string and combines it with the pre-filled greeting. When you call createGreeting("Well, hello there "), you’re not getting the final greeting string; you’re getting a new function (firstGreeting) that has the “Well, hello there ” greeting already “baked in.” You can then call firstGreeting with different names to get the complete greeting. The same principle applies to secondGreeting, prefilling a different initial greeting. The type hints help show the flow: createGreeting takes a string and returns a function that takes a string and returns a string.

JavaScript

<span>const</span> <span>createGreeting</span> <span>=</span> <span>(</span><span>greeting</span><span>)</span> <span>=></span> <span>{</span>
<span>return </span><span>(</span><span>name</span><span>)</span> <span>=></span> <span>{</span>
<span>return</span> <span>`</span><span>${</span><span>greeting</span><span>}</span><span> </span><span>${</span><span>name</span><span>}</span><span>`</span><span>;</span>
<span>};</span>
<span>};</span>
<span>const</span> <span>firstGreeting</span> <span>=</span> <span>createGreeting</span><span>(</span><span>"</span><span>Well, hello there </span><span>"</span><span>);</span>
<span>const</span> <span>secondGreeting</span> <span>=</span> <span>createGreeting</span><span>(</span><span>"</span><span>Hola </span><span>"</span><span>);</span>
<span>console</span><span>.</span><span>log</span><span>(</span><span>firstGreeting</span><span>(</span><span>"</span><span>Remi</span><span>"</span><span>));</span>
<span>console</span><span>.</span><span>log</span><span>(</span><span>secondGreeting</span><span>(</span><span>"</span><span>Ana</span><span>"</span><span>));</span>
<span>const</span> <span>createGreeting</span> <span>=</span> <span>(</span><span>greeting</span><span>)</span> <span>=></span> <span>{</span>
  <span>return </span><span>(</span><span>name</span><span>)</span> <span>=></span> <span>{</span>
    <span>return</span> <span>`</span><span>${</span><span>greeting</span><span>}</span><span> </span><span>${</span><span>name</span><span>}</span><span>`</span><span>;</span>
  <span>};</span>
<span>};</span>

<span>const</span> <span>firstGreeting</span> <span>=</span> <span>createGreeting</span><span>(</span><span>"</span><span>Well, hello there </span><span>"</span><span>);</span>
<span>const</span> <span>secondGreeting</span> <span>=</span> <span>createGreeting</span><span>(</span><span>"</span><span>Hola </span><span>"</span><span>);</span>
<span>console</span><span>.</span><span>log</span><span>(</span><span>firstGreeting</span><span>(</span><span>"</span><span>Remi</span><span>"</span><span>));</span>
<span>console</span><span>.</span><span>log</span><span>(</span><span>secondGreeting</span><span>(</span><span>"</span><span>Ana</span><span>"</span><span>));</span>
const createGreeting = (greeting) => { return (name) => { return `${greeting} ${name}`; }; }; const firstGreeting = createGreeting("Well, hello there "); const secondGreeting = createGreeting("Hola "); console.log(firstGreeting("Remi")); console.log(secondGreeting("Ana"));

Enter fullscreen mode Exit fullscreen mode

The JavaScript snippet achieves the same result using a concise arrow function syntax. createGreeting takes a greeting and returns another arrow function that takes a name. This inner function uses template literals (backticks) to create the final greeting string. Like the Python example, calling createGreeting with a greeting creates a new, specialized function (firstGreeting, secondGreeting) with that greeting pre-applied. The nested arrow functions clearly illustrate the process of creating a function that returns another function.

Go

<span>package</span> <span>main</span>
<span>import</span> <span>"fmt"</span>
<span>func</span> <span>createGreeting</span><span>(</span><span>greeting</span> <span>string</span><span>)</span> <span>func</span><span>(</span><span>string</span><span>)</span> <span>string</span> <span>{</span>
<span>return</span> <span>func</span><span>(</span><span>name</span> <span>string</span><span>)</span> <span>string</span> <span>{</span>
<span>return</span> <span>fmt</span><span>.</span><span>Sprintf</span><span>(</span><span>"%s %s"</span><span>,</span> <span>greeting</span><span>,</span> <span>name</span><span>)</span>
<span>}</span>
<span>}</span>
<span>func</span> <span>main</span><span>()</span> <span>{</span>
<span>firstGreeting</span> <span>:=</span> <span>createGreeting</span><span>(</span><span>"Well, hello there "</span><span>)</span>
<span>secondGreeting</span> <span>:=</span> <span>createGreeting</span><span>(</span><span>"Hola "</span><span>)</span>
<span>fmt</span><span>.</span><span>Println</span><span>(</span><span>firstGreeting</span><span>(</span><span>"Remi"</span><span>))</span>
<span>fmt</span><span>.</span><span>Println</span><span>(</span><span>secondGreeting</span><span>(</span><span>"Ana"</span><span>))</span>
<span>}</span>
<span>package</span> <span>main</span>

<span>import</span> <span>"fmt"</span>


<span>func</span> <span>createGreeting</span><span>(</span><span>greeting</span> <span>string</span><span>)</span> <span>func</span><span>(</span><span>string</span><span>)</span> <span>string</span> <span>{</span>
    <span>return</span> <span>func</span><span>(</span><span>name</span> <span>string</span><span>)</span> <span>string</span> <span>{</span>
            <span>return</span> <span>fmt</span><span>.</span><span>Sprintf</span><span>(</span><span>"%s %s"</span><span>,</span> <span>greeting</span><span>,</span> <span>name</span><span>)</span>
    <span>}</span>
<span>}</span>

<span>func</span> <span>main</span><span>()</span> <span>{</span>
    <span>firstGreeting</span> <span>:=</span> <span>createGreeting</span><span>(</span><span>"Well, hello there "</span><span>)</span>
    <span>secondGreeting</span> <span>:=</span> <span>createGreeting</span><span>(</span><span>"Hola "</span><span>)</span>
    <span>fmt</span><span>.</span><span>Println</span><span>(</span><span>firstGreeting</span><span>(</span><span>"Remi"</span><span>))</span>
    <span>fmt</span><span>.</span><span>Println</span><span>(</span><span>secondGreeting</span><span>(</span><span>"Ana"</span><span>))</span>
<span>}</span>
package main import "fmt" func createGreeting(greeting string) func(string) string { return func(name string) string { return fmt.Sprintf("%s %s", greeting, name) } } func main() { firstGreeting := createGreeting("Well, hello there ") secondGreeting := createGreeting("Hola ") fmt.Println(firstGreeting("Remi")) fmt.Println(secondGreeting("Ana")) }

Enter fullscreen mode Exit fullscreen mode

The Go snippet implements partial application in a similar manner. createGreeting takes a greeting string and returns a function that takes a name string and returns the combined string. Go’s explicit type signature, func(string) string, clearly indicates that createGreeting returns a function. The use of fmt.Sprintf is Go’s way of formatting strings, analogous to Python’s f-strings and JavaScript’s template literals. The result is the same: firstGreeting and secondGreeting become specialized functions with their respective greetings pre-filled. Go’s syntax, while slightly more verbose due to type declarations, achieves the same functional goal.

5. Currying

Currying is a technique closely related to partial application, but with a subtle, yet important, difference. While partial application allows you to pre-fill any number of arguments, currying transforms a function that takes multiple arguments into a sequence of functions, each taking a single argument. Each function in the sequence returns the next function in the sequence, until all arguments have been supplied, at which point the final result is returned. Currying isn’t built-in to any of these languages; we need to implement a curry function ourselves.

Python

<span>def</span> <span>curry</span><span>(</span><span>fn</span><span>):</span>
<span>def</span> <span>curried</span><span>(</span><span>*</span><span>args</span><span>):</span>
<span>if</span> <span>len</span><span>(</span><span>args</span><span>)</span> <span>>=</span> <span>fn</span><span>.</span><span>__code__</span><span>.</span><span>co_argcount</span><span>:</span>
<span>return</span> <span>fn</span><span>(</span><span>*</span><span>args</span><span>)</span>
<span>else</span><span>:</span>
<span>return</span> <span>lambda</span> <span>*</span><span>args2</span><span>:</span> <span>curried</span><span>(</span><span>*</span><span>(</span><span>args</span> <span>+</span> <span>args2</span><span>))</span>
<span>return</span> <span>curried</span>
<span>def</span> <span>add</span><span>(</span><span>a</span><span>:</span> <span>int</span><span>,</span> <span>b</span><span>:</span> <span>int</span><span>,</span> <span>c</span><span>:</span> <span>int</span><span>)</span> <span>-></span> <span>int</span><span>:</span>
<span>return</span> <span>a</span> <span>+</span> <span>b</span> <span>+</span> <span>c</span>
<span>result</span> <span>=</span> <span>curry</span><span>(</span><span>add</span><span>)(</span><span>1</span><span>)(</span><span>2</span><span>)(</span><span>3</span><span>)</span>
<span>print</span><span>(</span><span>result</span><span>)</span> <span># Output: 6 </span>
<span>def</span> <span>curry</span><span>(</span><span>fn</span><span>):</span>
    <span>def</span> <span>curried</span><span>(</span><span>*</span><span>args</span><span>):</span>
        <span>if</span> <span>len</span><span>(</span><span>args</span><span>)</span> <span>>=</span> <span>fn</span><span>.</span><span>__code__</span><span>.</span><span>co_argcount</span><span>:</span>
            <span>return</span> <span>fn</span><span>(</span><span>*</span><span>args</span><span>)</span>
        <span>else</span><span>:</span>
            <span>return</span> <span>lambda</span> <span>*</span><span>args2</span><span>:</span> <span>curried</span><span>(</span><span>*</span><span>(</span><span>args</span> <span>+</span> <span>args2</span><span>))</span>

    <span>return</span> <span>curried</span>


<span>def</span> <span>add</span><span>(</span><span>a</span><span>:</span> <span>int</span><span>,</span> <span>b</span><span>:</span> <span>int</span><span>,</span> <span>c</span><span>:</span> <span>int</span><span>)</span> <span>-></span> <span>int</span><span>:</span>
    <span>return</span> <span>a</span> <span>+</span> <span>b</span> <span>+</span> <span>c</span>


<span>result</span> <span>=</span> <span>curry</span><span>(</span><span>add</span><span>)(</span><span>1</span><span>)(</span><span>2</span><span>)(</span><span>3</span><span>)</span>
<span>print</span><span>(</span><span>result</span><span>)</span>  <span># Output: 6 </span>
def curry(fn): def curried(*args): if len(args) >= fn.__code__.co_argcount: return fn(*args) else: return lambda *args2: curried(*(args + args2)) return curried def add(a: int, b: int, c: int) -> int: return a + b + c result = curry(add)(1)(2)(3) print(result) # Output: 6

Enter fullscreen mode Exit fullscreen mode

The Python snippet implements a general-purpose curry function. This function is more complex than the previous examples because it needs to handle functions with an arbitrary number of arguments. It uses fn.__code__.co_argcount to determine the number of arguments the original function (fn) expects. The inner curried function uses *args to collect arguments. If enough arguments have been collected (the length of args is greater or equal to the number of arguments that fn expects), it calls the original function fn with those arguments. Otherwise, it returns a new lambda function that takes more arguments (*args2), combines them with the existing arguments (args + args2), and recursively calls curried again. This recursive process continues until all arguments are provided. The add function, which takes three arguments, is then curried and called with one argument at a time: curry(add)(1)(2)(3).

JavaScript

<span>function</span> <span>curry</span><span>(</span><span>fn</span><span>)</span> <span>{</span>
<span>return</span> <span>function</span> <span>curried</span><span>(...</span><span>args</span><span>)</span> <span>{</span>
<span>if </span><span>(</span><span>args</span><span>.</span><span>length</span> <span>>=</span> <span>fn</span><span>.</span><span>length</span><span>)</span> <span>{</span>
<span>return</span> <span>fn</span><span>.</span><span>apply</span><span>(</span><span>this</span><span>,</span> <span>args</span><span>);</span>
<span>}</span> <span>else</span> <span>{</span>
<span>return </span><span>(...</span><span>args2</span><span>)</span> <span>=></span> <span>curried</span><span>.</span><span>apply</span><span>(</span><span>this</span><span>,</span> <span>args</span><span>.</span><span>concat</span><span>(</span><span>args2</span><span>));</span>
<span>}</span>
<span>};</span>
<span>}</span>
<span>function</span> <span>add</span><span>(</span><span>a</span><span>,</span> <span>b</span><span>,</span> <span>c</span><span>)</span> <span>{</span>
<span>return</span> <span>a</span> <span>+</span> <span>b</span> <span>+</span> <span>c</span><span>;</span>
<span>}</span>
<span>const</span> <span>result</span> <span>=</span> <span>curry</span><span>(</span><span>add</span><span>)(</span><span>1</span><span>)(</span><span>2</span><span>)(</span><span>3</span><span>);</span>
<span>console</span><span>.</span><span>log</span><span>(</span><span>result</span><span>);</span> <span>// Output: 6</span>
<span>function</span> <span>curry</span><span>(</span><span>fn</span><span>)</span> <span>{</span>
  <span>return</span> <span>function</span> <span>curried</span><span>(...</span><span>args</span><span>)</span> <span>{</span>
    <span>if </span><span>(</span><span>args</span><span>.</span><span>length</span> <span>>=</span> <span>fn</span><span>.</span><span>length</span><span>)</span> <span>{</span>
      <span>return</span> <span>fn</span><span>.</span><span>apply</span><span>(</span><span>this</span><span>,</span> <span>args</span><span>);</span>
    <span>}</span> <span>else</span> <span>{</span>
      <span>return </span><span>(...</span><span>args2</span><span>)</span> <span>=></span> <span>curried</span><span>.</span><span>apply</span><span>(</span><span>this</span><span>,</span> <span>args</span><span>.</span><span>concat</span><span>(</span><span>args2</span><span>));</span>
    <span>}</span>
  <span>};</span>
<span>}</span>

<span>function</span> <span>add</span><span>(</span><span>a</span><span>,</span> <span>b</span><span>,</span> <span>c</span><span>)</span> <span>{</span>
  <span>return</span> <span>a</span> <span>+</span> <span>b</span> <span>+</span> <span>c</span><span>;</span>
<span>}</span>

<span>const</span> <span>result</span> <span>=</span> <span>curry</span><span>(</span><span>add</span><span>)(</span><span>1</span><span>)(</span><span>2</span><span>)(</span><span>3</span><span>);</span>
<span>console</span><span>.</span><span>log</span><span>(</span><span>result</span><span>);</span> <span>// Output: 6</span>
function curry(fn) { return function curried(...args) { if (args.length >= fn.length) { return fn.apply(this, args); } else { return (...args2) => curried.apply(this, args.concat(args2)); } }; } function add(a, b, c) { return a + b + c; } const result = curry(add)(1)(2)(3); console.log(result); // Output: 6

Enter fullscreen mode Exit fullscreen mode

The JavaScript snippet provides a similar curry function implementation. It uses fn.length to get the number of arguments the original function expects. The curried function uses the rest parameter syntax (...args) to gather arguments. If enough arguments are present, it calls the original function fn using apply (to handle the this context correctly). Otherwise, it returns a new function that takes more arguments (...args2), concatenates them with the existing arguments using concat, and recursively calls curried. Like the Python version, this allows us to call a curried function with one argument at a time, as shown with curry(add)(1)(2)(3). The Javascript and Python versions are strikingly similar.

Go

The Go snippet presents a significantly more complex implementation of curry. This is where the differences between Go’s static typing and the dynamic typing of Python and JavaScript become most apparent. Because Go is statically typed, creating a generic curry function that works with functions of any arity (number of arguments) and any type requires using the reflect package. Reflection allows us to inspect and manipulate types at runtime, which is necessary because the curry function doesn’t know the types of the function it’s currying beforehand.

<span>package</span> <span>main</span>
<span>import</span> <span>(</span>
<span>"fmt"</span>
<span>"reflect"</span>
<span>)</span>
<span>func</span> <span>curry</span><span>(</span><span>f</span> <span>interface</span><span>{})</span> <span>interface</span><span>{}</span> <span>{</span>
<span>ft</span> <span>:=</span> <span>reflect</span><span>.</span><span>TypeOf</span><span>(</span><span>f</span><span>)</span>
<span>if</span> <span>ft</span><span>.</span><span>Kind</span><span>()</span> <span>!=</span> <span>reflect</span><span>.</span><span>Func</span> <span>{</span>
<span>panic</span><span>(</span><span>"curry: argument must be a function"</span><span>)</span>
<span>}</span>
<span>numArgs</span> <span>:=</span> <span>ft</span><span>.</span><span>NumIn</span><span>()</span>
<span>args</span> <span>:=</span> <span>make</span><span>([]</span><span>reflect</span><span>.</span><span>Value</span><span>,</span> <span>0</span><span>,</span> <span>numArgs</span><span>)</span>
<span>var</span> <span>curried</span> <span>func</span><span>(</span><span>x</span> <span>reflect</span><span>.</span><span>Value</span><span>)</span> <span>interface</span><span>{}</span>
<span>curried</span> <span>=</span> <span>func</span><span>(</span><span>x</span> <span>reflect</span><span>.</span><span>Value</span><span>)</span> <span>interface</span><span>{}</span> <span>{</span>
<span>args</span> <span>=</span> <span>append</span><span>(</span><span>args</span><span>,</span> <span>x</span><span>)</span>
<span>if</span> <span>len</span><span>(</span><span>args</span><span>)</span> <span>==</span> <span>numArgs</span> <span>{</span>
<span>return</span> <span>reflect</span><span>.</span><span>ValueOf</span><span>(</span><span>f</span><span>)</span><span>.</span><span>Call</span><span>(</span><span>args</span><span>)[</span><span>0</span><span>]</span><span>.</span><span>Interface</span><span>()</span>
<span>}</span> <span>else</span> <span>{</span>
<span>return</span> <span>curried</span>
<span>}</span>
<span>}</span>
<span>return</span> <span>curried</span>
<span>}</span>
<span>func</span> <span>add</span><span>(</span><span>a</span><span>,</span> <span>b</span><span>,</span> <span>c</span> <span>int</span><span>)</span> <span>int</span> <span>{</span>
<span>return</span> <span>a</span> <span>+</span> <span>b</span> <span>+</span> <span>c</span>
<span>}</span>
<span>func</span> <span>main</span><span>()</span> <span>{</span>
<span>curriedAdd</span> <span>:=</span> <span>curry</span><span>(</span><span>add</span><span>)</span>
<span>add1</span> <span>:=</span> <span>curriedAdd</span><span>.</span><span>(</span><span>func</span><span>(</span><span>reflect</span><span>.</span><span>Value</span><span>)</span> <span>interface</span><span>{})(</span><span>reflect</span><span>.</span><span>ValueOf</span><span>(</span><span>1</span><span>))</span>
<span>add12</span> <span>:=</span> <span>add1</span><span>.</span><span>(</span><span>func</span><span>(</span><span>reflect</span><span>.</span><span>Value</span><span>)</span> <span>interface</span><span>{})(</span><span>reflect</span><span>.</span><span>ValueOf</span><span>(</span><span>2</span><span>))</span>
<span>result</span> <span>:=</span> <span>add12</span><span>.</span><span>(</span><span>func</span><span>(</span><span>reflect</span><span>.</span><span>Value</span><span>)</span> <span>interface</span><span>{})(</span><span>reflect</span><span>.</span><span>ValueOf</span><span>(</span><span>3</span><span>))</span><span>.</span><span>(</span><span>int</span><span>)</span>
<span>fmt</span><span>.</span><span>Println</span><span>(</span><span>result</span><span>)</span> <span>// Output: 6</span>
<span>}</span>
<span>package</span> <span>main</span>

<span>import</span> <span>(</span>
    <span>"fmt"</span>
    <span>"reflect"</span>
<span>)</span>


<span>func</span> <span>curry</span><span>(</span><span>f</span> <span>interface</span><span>{})</span> <span>interface</span><span>{}</span> <span>{</span>
    <span>ft</span> <span>:=</span> <span>reflect</span><span>.</span><span>TypeOf</span><span>(</span><span>f</span><span>)</span>
    <span>if</span> <span>ft</span><span>.</span><span>Kind</span><span>()</span> <span>!=</span> <span>reflect</span><span>.</span><span>Func</span> <span>{</span>
        <span>panic</span><span>(</span><span>"curry: argument must be a function"</span><span>)</span>
    <span>}</span>

    <span>numArgs</span> <span>:=</span> <span>ft</span><span>.</span><span>NumIn</span><span>()</span>
    <span>args</span> <span>:=</span> <span>make</span><span>([]</span><span>reflect</span><span>.</span><span>Value</span><span>,</span> <span>0</span><span>,</span> <span>numArgs</span><span>)</span>

    <span>var</span> <span>curried</span> <span>func</span><span>(</span><span>x</span> <span>reflect</span><span>.</span><span>Value</span><span>)</span> <span>interface</span><span>{}</span>
    <span>curried</span> <span>=</span> <span>func</span><span>(</span><span>x</span> <span>reflect</span><span>.</span><span>Value</span><span>)</span> <span>interface</span><span>{}</span> <span>{</span>
        <span>args</span> <span>=</span> <span>append</span><span>(</span><span>args</span><span>,</span> <span>x</span><span>)</span>
        <span>if</span> <span>len</span><span>(</span><span>args</span><span>)</span> <span>==</span> <span>numArgs</span> <span>{</span>
            <span>return</span> <span>reflect</span><span>.</span><span>ValueOf</span><span>(</span><span>f</span><span>)</span><span>.</span><span>Call</span><span>(</span><span>args</span><span>)[</span><span>0</span><span>]</span><span>.</span><span>Interface</span><span>()</span>
        <span>}</span> <span>else</span> <span>{</span>
            <span>return</span> <span>curried</span>
        <span>}</span>
    <span>}</span>

    <span>return</span> <span>curried</span>
<span>}</span>

<span>func</span> <span>add</span><span>(</span><span>a</span><span>,</span> <span>b</span><span>,</span> <span>c</span> <span>int</span><span>)</span> <span>int</span> <span>{</span>
    <span>return</span> <span>a</span> <span>+</span> <span>b</span> <span>+</span> <span>c</span>
<span>}</span>

<span>func</span> <span>main</span><span>()</span> <span>{</span>
    <span>curriedAdd</span> <span>:=</span> <span>curry</span><span>(</span><span>add</span><span>)</span>

    <span>add1</span> <span>:=</span> <span>curriedAdd</span><span>.</span><span>(</span><span>func</span><span>(</span><span>reflect</span><span>.</span><span>Value</span><span>)</span> <span>interface</span><span>{})(</span><span>reflect</span><span>.</span><span>ValueOf</span><span>(</span><span>1</span><span>))</span>
    <span>add12</span> <span>:=</span> <span>add1</span><span>.</span><span>(</span><span>func</span><span>(</span><span>reflect</span><span>.</span><span>Value</span><span>)</span> <span>interface</span><span>{})(</span><span>reflect</span><span>.</span><span>ValueOf</span><span>(</span><span>2</span><span>))</span>
    <span>result</span> <span>:=</span> <span>add12</span><span>.</span><span>(</span><span>func</span><span>(</span><span>reflect</span><span>.</span><span>Value</span><span>)</span> <span>interface</span><span>{})(</span><span>reflect</span><span>.</span><span>ValueOf</span><span>(</span><span>3</span><span>))</span><span>.</span><span>(</span><span>int</span><span>)</span>

    <span>fmt</span><span>.</span><span>Println</span><span>(</span><span>result</span><span>)</span> <span>// Output: 6</span>
<span>}</span>
package main import ( "fmt" "reflect" ) func curry(f interface{}) interface{} { ft := reflect.TypeOf(f) if ft.Kind() != reflect.Func { panic("curry: argument must be a function") } numArgs := ft.NumIn() args := make([]reflect.Value, 0, numArgs) var curried func(x reflect.Value) interface{} curried = func(x reflect.Value) interface{} { args = append(args, x) if len(args) == numArgs { return reflect.ValueOf(f).Call(args)[0].Interface() } else { return curried } } return curried } func add(a, b, c int) int { return a + b + c } func main() { curriedAdd := curry(add) add1 := curriedAdd.(func(reflect.Value) interface{})(reflect.ValueOf(1)) add12 := add1.(func(reflect.Value) interface{})(reflect.ValueOf(2)) result := add12.(func(reflect.Value) interface{})(reflect.ValueOf(3)).(int) fmt.Println(result) // Output: 6 }

Enter fullscreen mode Exit fullscreen mode

The curry function first checks if the input f is actually a function using reflect.TypeOf(f).Kind() != reflect.Func. It then determines the number of expected arguments using ft.NumIn(). It uses a slice args (of type reflect.Value) to store the accumulated arguments. The curried function (a closure) is defined recursively. When called with an argument x, it appends x to args. If enough arguments have been collected, it calls the original function using reflect.ValueOf(f).Call(args)[0].Interface(). This line is crucial: it converts the function f to a reflect.Value, calls it with the collected arguments, extracts the result (which is also a reflect.Value), and then converts it back to a regular Go interface{} using .Interface(). If not enough arguments have been collected, it returns itself (curried), continuing the currying process.

The main function shows how to use the curried function. Because the curry function returns the most generic type interface{}, we need multiple type assertions (e.g., .(func(reflect.Value) interface{})) to convert the intermediate curried functions to their correct types before we can call them. This is much more verbose than the Python and JavaScript examples, highlighting the added complexity of implementing currying in a statically-typed language without generics (prior to Go 1.18). The final result is retrieved and printed, demonstrating that the currying works, but at the cost of significantly more complex code. This example clearly shows that functional programming patterns like currying, while possible in Go, are often more natural and concise in dynamically typed languages.

6. Immutability

Immutability is a core principle of functional programming. An immutable object is one whose state cannot be changed after it’s created. This contrasts with mutable objects, which can be modified in place. Immutability simplifies reasoning about code, prevents unintended side effects, and is crucial for concurrent programming (as immutable data is inherently thread-safe). Different languages have varying levels of built-in support for immutability.

Python

<span>import</span> <span>copy</span>
<span>points1</span> <span>=</span> <span>[{</span><span>"</span><span>x</span><span>"</span><span>:</span> <span>1</span><span>,</span> <span>"</span><span>y</span><span>"</span><span>:</span> <span>2</span><span>},</span> <span>{</span><span>"</span><span>x</span><span>"</span><span>:</span> <span>3</span><span>,</span> <span>"</span><span>y</span><span>"</span><span>:</span> <span>4</span><span>}]</span>
<span># Shallow Copy </span><span>points2</span> <span>=</span> <span>copy</span><span>.</span><span>copy</span><span>(</span><span>points1</span><span>)</span>
<span>points2</span><span>.</span><span>append</span><span>({</span><span>"</span><span>x</span><span>"</span><span>:</span> <span>5</span><span>,</span> <span>"</span><span>y</span><span>"</span><span>:</span> <span>6</span><span>})</span> <span># Modifies only points2 </span><span>points2</span><span>[</span><span>0</span><span>][</span><span>"</span><span>x</span><span>"</span><span>]</span> <span>=</span> <span>10</span> <span># Modifies the object in both lists </span>
<span>print</span><span>(</span><span>points1</span><span>)</span> <span># Output: [{'x': 10, 'y': 2}, {'x': 3, 'y': 4}] (affected!) </span><span>print</span><span>(</span><span>points2</span><span>)</span> <span># Output: [{'x': 10, 'y': 2}, {'x': 3, 'y': 4}, {'x': 5, 'y': 6}] </span>
<span># Deep Copy </span><span>points3</span> <span>=</span> <span>copy</span><span>.</span><span>deepcopy</span><span>(</span><span>points1</span><span>)</span>
<span>points3</span><span>[</span><span>0</span><span>][</span><span>"</span><span>x</span><span>"</span><span>]</span> <span>=</span> <span>20</span> <span># Modifies only points3 </span>
<span>print</span><span>(</span><span>points1</span><span>)</span> <span># Output: [{'x': 10, 'y': 2}, {'x': 3, 'y': 4}] (unaffected) </span><span>print</span><span>(</span><span>points3</span><span>)</span> <span># Output: [{'x': 20, 'y': 2}, {'x': 3, 'y': 4}] </span>
<span>import</span> <span>copy</span>

<span>points1</span> <span>=</span> <span>[{</span><span>"</span><span>x</span><span>"</span><span>:</span> <span>1</span><span>,</span> <span>"</span><span>y</span><span>"</span><span>:</span> <span>2</span><span>},</span> <span>{</span><span>"</span><span>x</span><span>"</span><span>:</span> <span>3</span><span>,</span> <span>"</span><span>y</span><span>"</span><span>:</span> <span>4</span><span>}]</span>

<span># Shallow Copy </span><span>points2</span> <span>=</span> <span>copy</span><span>.</span><span>copy</span><span>(</span><span>points1</span><span>)</span>
<span>points2</span><span>.</span><span>append</span><span>({</span><span>"</span><span>x</span><span>"</span><span>:</span> <span>5</span><span>,</span> <span>"</span><span>y</span><span>"</span><span>:</span> <span>6</span><span>})</span>  <span># Modifies only points2 </span><span>points2</span><span>[</span><span>0</span><span>][</span><span>"</span><span>x</span><span>"</span><span>]</span> <span>=</span> <span>10</span>  <span># Modifies the object in both lists </span>
<span>print</span><span>(</span><span>points1</span><span>)</span>  <span># Output: [{'x': 10, 'y': 2}, {'x': 3, 'y': 4}] (affected!) </span><span>print</span><span>(</span><span>points2</span><span>)</span>  <span># Output: [{'x': 10, 'y': 2}, {'x': 3, 'y': 4}, {'x': 5, 'y': 6}] </span>
<span># Deep Copy </span><span>points3</span> <span>=</span> <span>copy</span><span>.</span><span>deepcopy</span><span>(</span><span>points1</span><span>)</span>
<span>points3</span><span>[</span><span>0</span><span>][</span><span>"</span><span>x</span><span>"</span><span>]</span> <span>=</span> <span>20</span>  <span># Modifies only points3 </span>
<span>print</span><span>(</span><span>points1</span><span>)</span>  <span># Output: [{'x': 10, 'y': 2}, {'x': 3, 'y': 4}] (unaffected) </span><span>print</span><span>(</span><span>points3</span><span>)</span>  <span># Output: [{'x': 20, 'y': 2}, {'x': 3, 'y': 4}] </span>
import copy points1 = [{"x": 1, "y": 2}, {"x": 3, "y": 4}] # Shallow Copy points2 = copy.copy(points1) points2.append({"x": 5, "y": 6}) # Modifies only points2 points2[0]["x"] = 10 # Modifies the object in both lists print(points1) # Output: [{'x': 10, 'y': 2}, {'x': 3, 'y': 4}] (affected!) print(points2) # Output: [{'x': 10, 'y': 2}, {'x': 3, 'y': 4}, {'x': 5, 'y': 6}] # Deep Copy points3 = copy.deepcopy(points1) points3[0]["x"] = 20 # Modifies only points3 print(points1) # Output: [{'x': 10, 'y': 2}, {'x': 3, 'y': 4}] (unaffected) print(points3) # Output: [{'x': 20, 'y': 2}, {'x': 3, 'y': 4}]

Enter fullscreen mode Exit fullscreen mode

Python’s built-in data structures, like lists and dictionaries, are mutable. This means you can modify them directly after creation. The Python snippet highlights the importance of understanding the difference between shallow and deep copies when working with nested mutable objects.

  • Shallow Copy (copy.copy()): A shallow copy creates a new top-level object, but the elements within that object are still references to the original objects. So, if you have a list of dictionaries, a shallow copy will create a new list, but the dictionaries inside the new list will be the same dictionaries as in the original list. Modifying a nested object in the shallow copy will affect the original object as well. As shown, appending to points2 affects only the copy because append creates a new array, but modifying points2[0]["x"] modifies the underlying object referenced by both points1 and points2.

  • Deep Copy (copy.deepcopy()): A deep copy recursively creates new copies of all objects, including nested ones. This means modifying a nested object in a deep copy will not affect the original object. As shown, after a deep copy, modifying points3[0]["x"] only affects points3, leaving points1 unchanged. You need to explicitly use copy.deepcopy() to achieve true immutability with nested mutable objects in Python.

JavaScript

<span>const</span> <span>points1</span> <span>=</span> <span>[{</span> <span>x</span><span>:</span> <span>1</span><span>,</span> <span>y</span><span>:</span> <span>2</span> <span>},</span> <span>{</span> <span>x</span><span>:</span> <span>3</span><span>,</span> <span>y</span><span>:</span> <span>4</span> <span>}];</span>
<span>const</span> <span>points2</span> <span>=</span> <span>[...</span><span>points1</span><span>];</span> <span>// Creates a shallow copy</span>
<span>points2</span><span>.</span><span>push</span><span>({</span> <span>x</span><span>:</span> <span>5</span><span>,</span> <span>y</span><span>:</span> <span>6</span> <span>});</span> <span>// Modifies only points2</span>
<span>points2</span><span>[</span><span>0</span><span>].</span><span>x</span> <span>=</span> <span>10</span><span>;</span> <span>// Modifies the object in both arrays</span>
<span>console</span><span>.</span><span>log</span><span>(</span><span>points1</span><span>);</span> <span>// Output: [{ x: 10, y: 2 }, { x: 3, y: 4 }] (affected!)</span>
<span>console</span><span>.</span><span>log</span><span>(</span><span>points2</span><span>);</span> <span>// Output: [{ x: 10, y: 2 }, { x: 3, y: 4 }, { x: 5, y: 6 }]</span>
<span>const</span> <span>points1</span> <span>=</span> <span>[{</span> <span>x</span><span>:</span> <span>1</span><span>,</span> <span>y</span><span>:</span> <span>2</span> <span>},</span> <span>{</span> <span>x</span><span>:</span> <span>3</span><span>,</span> <span>y</span><span>:</span> <span>4</span> <span>}];</span>
<span>const</span> <span>points2</span> <span>=</span> <span>[...</span><span>points1</span><span>];</span> <span>// Creates a shallow copy</span>

<span>points2</span><span>.</span><span>push</span><span>({</span> <span>x</span><span>:</span> <span>5</span><span>,</span> <span>y</span><span>:</span> <span>6</span> <span>});</span> <span>// Modifies only points2</span>
<span>points2</span><span>[</span><span>0</span><span>].</span><span>x</span> <span>=</span> <span>10</span><span>;</span> <span>// Modifies the object in both arrays</span>

<span>console</span><span>.</span><span>log</span><span>(</span><span>points1</span><span>);</span> <span>// Output: [{ x: 10, y: 2 }, { x: 3, y: 4 }] (affected!)</span>
<span>console</span><span>.</span><span>log</span><span>(</span><span>points2</span><span>);</span> <span>// Output: [{ x: 10, y: 2 }, { x: 3, y: 4 }, { x: 5, y: 6 }]</span>
const points1 = [{ x: 1, y: 2 }, { x: 3, y: 4 }]; const points2 = [...points1]; // Creates a shallow copy points2.push({ x: 5, y: 6 }); // Modifies only points2 points2[0].x = 10; // Modifies the object in both arrays console.log(points1); // Output: [{ x: 10, y: 2 }, { x: 3, y: 4 }] (affected!) console.log(points2); // Output: [{ x: 10, y: 2 }, { x: 3, y: 4 }, { x: 5, y: 6 }]

Enter fullscreen mode Exit fullscreen mode

JavaScript, like Python, has mutable objects (arrays and objects) by default. The JavaScript snippet uses the spread operator (...) to create a shallow copy of an array of objects.

  • Spread Operator for Arrays: The spread operator, when used with an array, creates a shallow copy. Similar to Python’s copy.copy(), it creates a new array, but the objects within the array are still references to the same objects in the original array. Appending to points2 doesn’t modify points1, as a new array instance is created, but changing points2[0].x does modify the corresponding object in points1 because it’s a shared reference.

  • Deep Copying in JavaScript: JavaScript doesn’t have a built-in deep copy function like Python’s copy.deepcopy(). You typically need to use a custom function or a library (like Lodash’s _.cloneDeep) to perform a deep copy. One common (but potentially problematic) approach is to use JSON.parse(JSON.stringify(object)), but this only works for objects that can be safely serialized to JSON (no functions, circular references, etc.). The lack of a standard, built-in deep copy mechanism is a notable weakness of JavaScript in terms of supporting immutability.

Go

<span>package</span> <span>main</span>
<span>import</span> <span>"fmt"</span>
<span>type</span> <span>Point</span> <span>struct</span> <span>{</span>
<span>X</span> <span>int</span>
<span>Y</span> <span>int</span>
<span>}</span>
<span>func</span> <span>main</span><span>()</span> <span>{</span>
<span>points1</span> <span>:=</span> <span>[]</span><span>Point</span><span>{{</span><span>1</span><span>,</span> <span>2</span><span>},</span> <span>{</span><span>3</span><span>,</span> <span>4</span><span>}}</span>
<span>points2</span> <span>:=</span> <span>points1</span> <span>// Creates a copy of the slice header and underlying array</span>
<span>// Appending creates a new slice, doesn't modify points1</span>
<span>points2</span> <span>=</span> <span>append</span><span>(</span><span>points2</span><span>,</span> <span>Point</span><span>{</span><span>5</span><span>,</span> <span>6</span><span>})</span>
<span>// Modifying an element in points2 creates a copy of that element.</span>
<span>points2</span><span>[</span><span>0</span><span>]</span><span>.</span><span>X</span> <span>=</span> <span>10</span>
<span>fmt</span><span>.</span><span>Println</span><span>(</span><span>points1</span><span>)</span> <span>// Output: [{1 2} {3 4}] (original unaffected)</span>
<span>fmt</span><span>.</span><span>Println</span><span>(</span><span>points2</span><span>)</span> <span>// Output: [{10 2} {3 4} {5 6}]</span>
<span>}</span>
<span>package</span> <span>main</span>

<span>import</span> <span>"fmt"</span>

<span>type</span> <span>Point</span> <span>struct</span> <span>{</span>
    <span>X</span> <span>int</span>
    <span>Y</span> <span>int</span>
<span>}</span>

<span>func</span> <span>main</span><span>()</span> <span>{</span>
    <span>points1</span> <span>:=</span> <span>[]</span><span>Point</span><span>{{</span><span>1</span><span>,</span> <span>2</span><span>},</span> <span>{</span><span>3</span><span>,</span> <span>4</span><span>}}</span>
    <span>points2</span> <span>:=</span> <span>points1</span> <span>// Creates a copy of the slice header and underlying array</span>

    <span>// Appending creates a new slice, doesn't modify points1</span>
    <span>points2</span> <span>=</span> <span>append</span><span>(</span><span>points2</span><span>,</span> <span>Point</span><span>{</span><span>5</span><span>,</span> <span>6</span><span>})</span>

    <span>// Modifying an element in points2 creates a copy of that element.</span>
    <span>points2</span><span>[</span><span>0</span><span>]</span><span>.</span><span>X</span> <span>=</span> <span>10</span>

    <span>fmt</span><span>.</span><span>Println</span><span>(</span><span>points1</span><span>)</span> <span>// Output: [{1 2} {3 4}] (original unaffected)</span>
    <span>fmt</span><span>.</span><span>Println</span><span>(</span><span>points2</span><span>)</span> <span>// Output: [{10 2} {3 4} {5 6}]</span>
<span>}</span>
package main import "fmt" type Point struct { X int Y int } func main() { points1 := []Point{{1, 2}, {3, 4}} points2 := points1 // Creates a copy of the slice header and underlying array // Appending creates a new slice, doesn't modify points1 points2 = append(points2, Point{5, 6}) // Modifying an element in points2 creates a copy of that element. points2[0].X = 10 fmt.Println(points1) // Output: [{1 2} {3 4}] (original unaffected) fmt.Println(points2) // Output: [{10 2} {3 4} {5 6}] }

Enter fullscreen mode Exit fullscreen mode

Go takes a different approach to immutability. Go’s structs are value types. When you assign a struct to a new variable or pass it to a function, a copy of the struct is created. This promotes immutability by default.

  • Value Types: In the Go snippet, Point is a struct. When points2 := points1 is executed, points2 receives a copy of the slice header. Importantly, in this case, the underlying array elements (the Point structs) are also copied because they are value types.

  • append: The append function in Go is designed to work well with immutability. When you append to a slice, Go might create a new underlying array if the existing array doesn’t have enough capacity. This means that append often returns a new slice, leaving the original slice untouched. As demonstrated, points2 = append(points2, Point{5, 6}) creates a new slice for points2, leaving points1 unmodified.

  • Modifying Struct Fields: Because of the value semantics of structs, changing a field within the struct inside a slice in Go doesn’t change the value of the struct in another.
    In the example provided, modifying points2, does not affect points1.

Go’s design, with its emphasis on value types for structs and the behavior of append, encourages immutability. While you can use pointers to create mutable behavior in Go, the language’s default behavior for structs promotes immutability, making it easier to write code with fewer side effects. This is a significant advantage of Go for functional programming.

7. Map, Filter, Reduce

Map, filter, and reduce are fundamental higher-order functions in functional programming that operate on collections of data (like lists or arrays). They provide a concise and declarative way to transform and process data without using explicit loops.

  • Map: Applies a given function to each element of a collection, producing a new collection with the transformed elements. The original collection remains unchanged.
  • Filter: Creates a new collection containing only the elements from the original collection that satisfy a given condition (a predicate function).
  • Reduce: Combines all elements of a collection into a single value using a specified function. This function takes an accumulator and the current element, updating the accumulator with each iteration.

Python

<span>from</span> <span>functools</span> <span>import</span> <span>reduce</span>
<span># Map: Square each number </span><span>numbers</span> <span>=</span> <span>[</span><span>1</span><span>,</span> <span>2</span><span>,</span> <span>3</span><span>,</span> <span>4</span><span>,</span> <span>5</span><span>]</span>
<span>squares</span> <span>=</span> <span>list</span><span>(</span><span>map</span><span>(</span><span>lambda</span> <span>n</span><span>:</span> <span>n</span> <span>*</span> <span>n</span><span>,</span> <span>numbers</span><span>))</span>
<span>print</span><span>(</span><span>"</span><span>Squares:</span><span>"</span><span>,</span> <span>squares</span><span>)</span>
<span># Filter: Get even numbers </span><span>evens</span> <span>=</span> <span>list</span><span>(</span><span>filter</span><span>(</span><span>lambda</span> <span>n</span><span>:</span> <span>n</span> <span>%</span> <span>2</span> <span>==</span> <span>0</span><span>,</span> <span>numbers</span><span>))</span>
<span>print</span><span>(</span><span>"</span><span>Evens:</span><span>"</span><span>,</span> <span>evens</span><span>)</span>
<span># Reduce: Sum all numbers </span><span>sum_of_numbers</span> <span>=</span> <span>reduce</span><span>(</span><span>lambda</span> <span>acc</span><span>,</span> <span>n</span><span>:</span> <span>acc</span> <span>+</span> <span>n</span><span>,</span> <span>numbers</span><span>,</span> <span>0</span><span>)</span> <span># 0 is the initial value </span><span>print</span><span>(</span><span>"</span><span>Sum:</span><span>"</span><span>,</span> <span>sum_of_numbers</span><span>)</span>
<span>from</span> <span>functools</span> <span>import</span> <span>reduce</span>

<span># Map: Square each number </span><span>numbers</span> <span>=</span> <span>[</span><span>1</span><span>,</span> <span>2</span><span>,</span> <span>3</span><span>,</span> <span>4</span><span>,</span> <span>5</span><span>]</span>
<span>squares</span> <span>=</span> <span>list</span><span>(</span><span>map</span><span>(</span><span>lambda</span> <span>n</span><span>:</span> <span>n</span> <span>*</span> <span>n</span><span>,</span> <span>numbers</span><span>))</span>
<span>print</span><span>(</span><span>"</span><span>Squares:</span><span>"</span><span>,</span> <span>squares</span><span>)</span>

<span># Filter: Get even numbers </span><span>evens</span> <span>=</span> <span>list</span><span>(</span><span>filter</span><span>(</span><span>lambda</span> <span>n</span><span>:</span> <span>n</span> <span>%</span> <span>2</span> <span>==</span> <span>0</span><span>,</span> <span>numbers</span><span>))</span>
<span>print</span><span>(</span><span>"</span><span>Evens:</span><span>"</span><span>,</span> <span>evens</span><span>)</span>

<span># Reduce: Sum all numbers </span><span>sum_of_numbers</span> <span>=</span> <span>reduce</span><span>(</span><span>lambda</span> <span>acc</span><span>,</span> <span>n</span><span>:</span> <span>acc</span> <span>+</span> <span>n</span><span>,</span> <span>numbers</span><span>,</span> <span>0</span><span>)</span>  <span># 0 is the initial value </span><span>print</span><span>(</span><span>"</span><span>Sum:</span><span>"</span><span>,</span> <span>sum_of_numbers</span><span>)</span>
from functools import reduce # Map: Square each number numbers = [1, 2, 3, 4, 5] squares = list(map(lambda n: n * n, numbers)) print("Squares:", squares) # Filter: Get even numbers evens = list(filter(lambda n: n % 2 == 0, numbers)) print("Evens:", evens) # Reduce: Sum all numbers sum_of_numbers = reduce(lambda acc, n: acc + n, numbers, 0) # 0 is the initial value print("Sum:", sum_of_numbers)

Enter fullscreen mode Exit fullscreen mode

Python has built-in support for map, filter, and reduce.

  • map: The map function takes a function and an iterable (like a list) as arguments. In the example, lambda n: n * n is an anonymous function (a lambda) that squares a number. map applies this function to each element of the numbers list. The result of map is an iterator, so we use list() to convert it to a list for printing.

  • filter: The filter function also takes a function and an iterable. The function (lambda n: n % 2 == 0) acts as a predicate, returning True for even numbers and False otherwise. filter returns an iterator containing only the elements for which the predicate returns True. Again, we use list() to convert it to a list.

  • reduce: reduce is not directly built-in; it’s part of the functools module. It takes a function, an iterable, and an optional initial value. The function (lambda acc, n: acc + n) takes the accumulator (acc) and the current element (n), returning the updated accumulator. reduce applies this function cumulatively to the items of the sequence, from left to right, so as to reduce the sequence to a single value. In the snippet, it calculates the sum of all numbers in the list.

JavaScript

<span>// Map: Square each number</span>
<span>const</span> <span>numbers</span> <span>=</span> <span>[</span><span>1</span><span>,</span> <span>2</span><span>,</span> <span>3</span><span>,</span> <span>4</span><span>,</span> <span>5</span><span>];</span>
<span>const</span> <span>squares</span> <span>=</span> <span>numbers</span><span>.</span><span>map</span><span>(</span><span>n</span> <span>=></span> <span>n</span> <span>*</span> <span>n</span><span>);</span>
<span>console</span><span>.</span><span>log</span><span>(</span><span>"</span><span>Squares:</span><span>"</span><span>,</span> <span>squares</span><span>);</span>
<span>// Filter: Get even numbers</span>
<span>const</span> <span>evens</span> <span>=</span> <span>numbers</span><span>.</span><span>filter</span><span>(</span><span>n</span> <span>=></span> <span>n</span> <span>%</span> <span>2</span> <span>===</span> <span>0</span><span>);</span>
<span>console</span><span>.</span><span>log</span><span>(</span><span>"</span><span>Evens:</span><span>"</span><span>,</span> <span>evens</span><span>);</span>
<span>// Reduce: Sum all numbers</span>
<span>const</span> <span>sum</span> <span>=</span> <span>numbers</span><span>.</span><span>reduce</span><span>((</span><span>acc</span><span>,</span> <span>n</span><span>)</span> <span>=></span> <span>acc</span> <span>+</span> <span>n</span><span>,</span> <span>0</span><span>);</span> <span>// 0 is the initial value</span>
<span>console</span><span>.</span><span>log</span><span>(</span><span>"</span><span>Sum:</span><span>"</span><span>,</span> <span>sum</span><span>);</span>
<span>// Map: Square each number</span>
<span>const</span> <span>numbers</span> <span>=</span> <span>[</span><span>1</span><span>,</span> <span>2</span><span>,</span> <span>3</span><span>,</span> <span>4</span><span>,</span> <span>5</span><span>];</span>
<span>const</span> <span>squares</span> <span>=</span> <span>numbers</span><span>.</span><span>map</span><span>(</span><span>n</span> <span>=></span> <span>n</span> <span>*</span> <span>n</span><span>);</span>
<span>console</span><span>.</span><span>log</span><span>(</span><span>"</span><span>Squares:</span><span>"</span><span>,</span> <span>squares</span><span>);</span>

<span>// Filter: Get even numbers</span>
<span>const</span> <span>evens</span> <span>=</span> <span>numbers</span><span>.</span><span>filter</span><span>(</span><span>n</span> <span>=></span> <span>n</span> <span>%</span> <span>2</span> <span>===</span> <span>0</span><span>);</span>
<span>console</span><span>.</span><span>log</span><span>(</span><span>"</span><span>Evens:</span><span>"</span><span>,</span> <span>evens</span><span>);</span>

<span>// Reduce: Sum all numbers</span>
<span>const</span> <span>sum</span> <span>=</span> <span>numbers</span><span>.</span><span>reduce</span><span>((</span><span>acc</span><span>,</span> <span>n</span><span>)</span> <span>=></span> <span>acc</span> <span>+</span> <span>n</span><span>,</span> <span>0</span><span>);</span> <span>// 0 is the initial value</span>
<span>console</span><span>.</span><span>log</span><span>(</span><span>"</span><span>Sum:</span><span>"</span><span>,</span> <span>sum</span><span>);</span>
// Map: Square each number const numbers = [1, 2, 3, 4, 5]; const squares = numbers.map(n => n * n); console.log("Squares:", squares); // Filter: Get even numbers const evens = numbers.filter(n => n % 2 === 0); console.log("Evens:", evens); // Reduce: Sum all numbers const sum = numbers.reduce((acc, n) => acc + n, 0); // 0 is the initial value console.log("Sum:", sum);

Enter fullscreen mode Exit fullscreen mode

JavaScript also provides map, filter, and reduce as built-in methods on arrays. This makes the syntax very concise and readable.

  • map: The map method is called directly on the numbers array. It takes a callback function (n => n * n) that’s applied to each element, creating a new array (squares) with the results.

  • filter: The filter method, similarly, is called on the array. It takes a predicate function (n => n % 2 === 0) and returns a new array (evens) containing only the elements that satisfy the predicate.

  • reduce: The reduce method is also called on the array. It takes a callback function ((acc, n) => acc + n) and an initial value (0). The callback function takes the accumulator (acc) and the current element (n), returning the updated accumulator. reduce iterates through the array, accumulating the result into the sum variable. The JavaScript syntax for these operations is very clean and directly integrated into the array object.

Go

<span>package</span> <span>main</span>
<span>import</span> <span>(</span>
<span>"fmt"</span>
<span>)</span>
<span>func</span> <span>Map</span><span>[</span><span>T</span><span>,</span> <span>U</span> <span>any</span><span>](</span><span>slice</span> <span>[]</span><span>T</span><span>,</span> <span>f</span> <span>func</span><span>(</span><span>T</span><span>)</span> <span>U</span><span>)</span> <span>[]</span><span>U</span> <span>{</span>
<span>result</span> <span>:=</span> <span>make</span><span>([]</span><span>U</span><span>,</span> <span>len</span><span>(</span><span>slice</span><span>))</span>
<span>for</span> <span>i</span><span>,</span> <span>v</span> <span>:=</span> <span>range</span> <span>slice</span> <span>{</span>
<span>result</span><span>[</span><span>i</span><span>]</span> <span>=</span> <span>f</span><span>(</span><span>v</span><span>)</span>
<span>}</span>
<span>return</span> <span>result</span>
<span>}</span>
<span>func</span> <span>Filter</span><span>[</span><span>T</span> <span>any</span><span>](</span><span>slice</span> <span>[]</span><span>T</span><span>,</span> <span>f</span> <span>func</span><span>(</span><span>T</span><span>)</span> <span>bool</span><span>)</span> <span>[]</span><span>T</span> <span>{</span>
<span>var</span> <span>result</span> <span>[]</span><span>T</span>
<span>for</span> <span>_</span><span>,</span> <span>v</span> <span>:=</span> <span>range</span> <span>slice</span> <span>{</span>
<span>if</span> <span>f</span><span>(</span><span>v</span><span>)</span> <span>{</span>
<span>result</span> <span>=</span> <span>append</span><span>(</span><span>result</span><span>,</span> <span>v</span><span>)</span>
<span>}</span>
<span>}</span>
<span>return</span> <span>result</span>
<span>}</span>
<span>func</span> <span>Reduce</span><span>[</span><span>T</span><span>,</span> <span>U</span> <span>any</span><span>](</span><span>slice</span> <span>[]</span><span>T</span><span>,</span> <span>initial</span> <span>U</span><span>,</span> <span>f</span> <span>func</span><span>(</span><span>U</span><span>,</span> <span>T</span><span>)</span> <span>U</span><span>)</span> <span>U</span> <span>{</span>
<span>result</span> <span>:=</span> <span>initial</span>
<span>for</span> <span>_</span><span>,</span> <span>v</span> <span>:=</span> <span>range</span> <span>slice</span> <span>{</span>
<span>result</span> <span>=</span> <span>f</span><span>(</span><span>result</span><span>,</span> <span>v</span><span>)</span>
<span>}</span>
<span>return</span> <span>result</span>
<span>}</span>
<span>func</span> <span>main</span><span>()</span> <span>{</span>
<span>numbers</span> <span>:=</span> <span>[]</span><span>int</span><span>{</span><span>1</span><span>,</span> <span>2</span><span>,</span> <span>3</span><span>,</span> <span>4</span><span>,</span> <span>5</span><span>}</span>
<span>// Map: Square each number</span>
<span>squares</span> <span>:=</span> <span>Map</span><span>(</span><span>numbers</span><span>,</span> <span>func</span><span>(</span><span>n</span> <span>int</span><span>)</span> <span>int</span> <span>{</span> <span>return</span> <span>n</span> <span>*</span> <span>n</span> <span>})</span>
<span>fmt</span><span>.</span><span>Println</span><span>(</span><span>"Squares:"</span><span>,</span> <span>squares</span><span>)</span>
<span>// Filter: Get even numbers</span>
<span>evens</span> <span>:=</span> <span>Filter</span><span>(</span><span>numbers</span><span>,</span> <span>func</span><span>(</span><span>n</span> <span>int</span><span>)</span> <span>bool</span> <span>{</span> <span>return</span> <span>n</span><span>%</span><span>2</span> <span>==</span> <span>0</span> <span>})</span>
<span>fmt</span><span>.</span><span>Println</span><span>(</span><span>"Evens:"</span><span>,</span> <span>evens</span><span>)</span>
<span>// Reduce: Sum all numbers</span>
<span>sum</span> <span>:=</span> <span>Reduce</span><span>(</span><span>numbers</span><span>,</span> <span>0</span><span>,</span> <span>func</span><span>(</span><span>acc</span> <span>int</span><span>,</span> <span>n</span> <span>int</span><span>)</span> <span>int</span> <span>{</span> <span>return</span> <span>acc</span> <span>+</span> <span>n</span> <span>})</span>
<span>fmt</span><span>.</span><span>Println</span><span>(</span><span>"Sum:"</span><span>,</span> <span>sum</span><span>)</span>
<span>}</span>
<span>package</span> <span>main</span>

<span>import</span> <span>(</span>
    <span>"fmt"</span>
<span>)</span>

<span>func</span> <span>Map</span><span>[</span><span>T</span><span>,</span> <span>U</span> <span>any</span><span>](</span><span>slice</span> <span>[]</span><span>T</span><span>,</span> <span>f</span> <span>func</span><span>(</span><span>T</span><span>)</span> <span>U</span><span>)</span> <span>[]</span><span>U</span> <span>{</span>
    <span>result</span> <span>:=</span> <span>make</span><span>([]</span><span>U</span><span>,</span> <span>len</span><span>(</span><span>slice</span><span>))</span>
    <span>for</span> <span>i</span><span>,</span> <span>v</span> <span>:=</span> <span>range</span> <span>slice</span> <span>{</span>
        <span>result</span><span>[</span><span>i</span><span>]</span> <span>=</span> <span>f</span><span>(</span><span>v</span><span>)</span>
    <span>}</span>
    <span>return</span> <span>result</span>
<span>}</span>

<span>func</span> <span>Filter</span><span>[</span><span>T</span> <span>any</span><span>](</span><span>slice</span> <span>[]</span><span>T</span><span>,</span> <span>f</span> <span>func</span><span>(</span><span>T</span><span>)</span> <span>bool</span><span>)</span> <span>[]</span><span>T</span> <span>{</span>
    <span>var</span> <span>result</span> <span>[]</span><span>T</span>
    <span>for</span> <span>_</span><span>,</span> <span>v</span> <span>:=</span> <span>range</span> <span>slice</span> <span>{</span>
        <span>if</span> <span>f</span><span>(</span><span>v</span><span>)</span> <span>{</span>
            <span>result</span> <span>=</span> <span>append</span><span>(</span><span>result</span><span>,</span> <span>v</span><span>)</span>
        <span>}</span>
    <span>}</span>
    <span>return</span> <span>result</span>
<span>}</span>

<span>func</span> <span>Reduce</span><span>[</span><span>T</span><span>,</span> <span>U</span> <span>any</span><span>](</span><span>slice</span> <span>[]</span><span>T</span><span>,</span> <span>initial</span> <span>U</span><span>,</span> <span>f</span> <span>func</span><span>(</span><span>U</span><span>,</span> <span>T</span><span>)</span> <span>U</span><span>)</span> <span>U</span> <span>{</span>
    <span>result</span> <span>:=</span> <span>initial</span>
    <span>for</span> <span>_</span><span>,</span> <span>v</span> <span>:=</span> <span>range</span> <span>slice</span> <span>{</span>
        <span>result</span> <span>=</span> <span>f</span><span>(</span><span>result</span><span>,</span> <span>v</span><span>)</span>
    <span>}</span>
    <span>return</span> <span>result</span>
<span>}</span>

<span>func</span> <span>main</span><span>()</span> <span>{</span>
    <span>numbers</span> <span>:=</span> <span>[]</span><span>int</span><span>{</span><span>1</span><span>,</span> <span>2</span><span>,</span> <span>3</span><span>,</span> <span>4</span><span>,</span> <span>5</span><span>}</span>

    <span>// Map: Square each number</span>
    <span>squares</span> <span>:=</span> <span>Map</span><span>(</span><span>numbers</span><span>,</span> <span>func</span><span>(</span><span>n</span> <span>int</span><span>)</span> <span>int</span> <span>{</span> <span>return</span> <span>n</span> <span>*</span> <span>n</span> <span>})</span>
    <span>fmt</span><span>.</span><span>Println</span><span>(</span><span>"Squares:"</span><span>,</span> <span>squares</span><span>)</span>

    <span>// Filter: Get even numbers</span>
    <span>evens</span> <span>:=</span> <span>Filter</span><span>(</span><span>numbers</span><span>,</span> <span>func</span><span>(</span><span>n</span> <span>int</span><span>)</span> <span>bool</span> <span>{</span> <span>return</span> <span>n</span><span>%</span><span>2</span> <span>==</span> <span>0</span> <span>})</span>
    <span>fmt</span><span>.</span><span>Println</span><span>(</span><span>"Evens:"</span><span>,</span> <span>evens</span><span>)</span>

    <span>// Reduce: Sum all numbers</span>
    <span>sum</span> <span>:=</span> <span>Reduce</span><span>(</span><span>numbers</span><span>,</span> <span>0</span><span>,</span> <span>func</span><span>(</span><span>acc</span> <span>int</span><span>,</span> <span>n</span> <span>int</span><span>)</span> <span>int</span> <span>{</span> <span>return</span> <span>acc</span> <span>+</span> <span>n</span> <span>})</span>
    <span>fmt</span><span>.</span><span>Println</span><span>(</span><span>"Sum:"</span><span>,</span> <span>sum</span><span>)</span>
<span>}</span>
package main import ( "fmt" ) func Map[T, U any](slice []T, f func(T) U) []U { result := make([]U, len(slice)) for i, v := range slice { result[i] = f(v) } return result } func Filter[T any](slice []T, f func(T) bool) []T { var result []T for _, v := range slice { if f(v) { result = append(result, v) } } return result } func Reduce[T, U any](slice []T, initial U, f func(U, T) U) U { result := initial for _, v := range slice { result = f(result, v) } return result } func main() { numbers := []int{1, 2, 3, 4, 5} // Map: Square each number squares := Map(numbers, func(n int) int { return n * n }) fmt.Println("Squares:", squares) // Filter: Get even numbers evens := Filter(numbers, func(n int) bool { return n%2 == 0 }) fmt.Println("Evens:", evens) // Reduce: Sum all numbers sum := Reduce(numbers, 0, func(acc int, n int) int { return acc + n }) fmt.Println("Sum:", sum) }

Enter fullscreen mode Exit fullscreen mode

Go, unlike Python and JavaScript, does not have built-in map, filter, and reduce functions. However, you can easily implement them using Go’s for...range loops and functions. The Go snippet shows generic implementations of Map, Filter, and Reduce using Go 1.18+ generics.

  • Map: The provided Map function takes a slice of type T, a function that transforms a T to a U, and it returns a slice of type U. The types T and U can be any types. It iterates through the input slice, applies the provided function f to each element, and stores the result in a new slice.

  • Filter: The Filter function takes a slice of type T and a predicate function (a function that returns a boolean). It iterates through the slice, and for each element where the predicate function returns true, it appends the element to a new slice.

  • Reduce: The Reduce function takes a slice of type T, an initial value of type U, and a function which takes a value of type U and a value of type T, returning another U.

While Go requires more code to achieve the same functionality as Python and JavaScript’s built-ins, the generic implementations provide flexibility and type safety. The use of anonymous functions (like func(n int) int { return n * n }) makes the code resemble the lambda expressions used in Python and JavaScript.

8. Function Composition

Function composition is the process of combining two or more functions to create a new function. The output of one function becomes the input of the next, forming a pipeline of operations. This is a powerful way to build complex logic from simpler, reusable building blocks, enhancing code modularity and readability. It avoids creating intermediate variables and nested function calls.

Python

<span>from</span> <span>functools</span> <span>import</span> <span>reduce</span>
<span>def</span> <span>compose</span><span>(</span><span>*</span><span>funcs</span><span>):</span>
<span>return</span> <span>lambda</span> <span>x</span><span>:</span> <span>reduce</span><span>(</span><span>lambda</span> <span>acc</span><span>,</span> <span>f</span><span>:</span> <span>f</span><span>(</span><span>acc</span><span>),</span> <span>reversed</span><span>(</span><span>funcs</span><span>),</span> <span>x</span><span>)</span>
<span>def</span> <span>add_one</span><span>(</span><span>x</span><span>):</span>
<span>return</span> <span>x</span> <span>+</span> <span>1</span>
<span>def</span> <span>square</span><span>(</span><span>x</span><span>):</span>
<span>return</span> <span>x</span> <span>*</span> <span>x</span>
<span>def</span> <span>multiply_by_two</span><span>(</span><span>x</span><span>):</span>
<span>return</span> <span>x</span> <span>*</span> <span>2</span>
<span>composed</span> <span>=</span> <span>compose</span><span>(</span><span>square</span><span>,</span> <span>multiply_by_two</span><span>,</span> <span>add_one</span><span>)</span> <span># Order is correct </span><span>result</span> <span>=</span> <span>composed</span><span>(</span><span>5</span><span>)</span> <span># ((5 + 1) * 2)^2 = 144 </span><span>print</span><span>(</span><span>"</span><span>Composed result:</span><span>"</span><span>,</span> <span>result</span><span>)</span>
<span>from</span> <span>functools</span> <span>import</span> <span>reduce</span>


<span>def</span> <span>compose</span><span>(</span><span>*</span><span>funcs</span><span>):</span>
    <span>return</span> <span>lambda</span> <span>x</span><span>:</span> <span>reduce</span><span>(</span><span>lambda</span> <span>acc</span><span>,</span> <span>f</span><span>:</span> <span>f</span><span>(</span><span>acc</span><span>),</span> <span>reversed</span><span>(</span><span>funcs</span><span>),</span> <span>x</span><span>)</span>


<span>def</span> <span>add_one</span><span>(</span><span>x</span><span>):</span>
    <span>return</span> <span>x</span> <span>+</span> <span>1</span>


<span>def</span> <span>square</span><span>(</span><span>x</span><span>):</span>
    <span>return</span> <span>x</span> <span>*</span> <span>x</span>


<span>def</span> <span>multiply_by_two</span><span>(</span><span>x</span><span>):</span>
    <span>return</span> <span>x</span> <span>*</span> <span>2</span>


<span>composed</span> <span>=</span> <span>compose</span><span>(</span><span>square</span><span>,</span> <span>multiply_by_two</span><span>,</span> <span>add_one</span><span>)</span>  <span># Order is correct </span><span>result</span> <span>=</span> <span>composed</span><span>(</span><span>5</span><span>)</span>  <span># ((5 + 1) * 2)^2 = 144 </span><span>print</span><span>(</span><span>"</span><span>Composed result:</span><span>"</span><span>,</span> <span>result</span><span>)</span>
from functools import reduce def compose(*funcs): return lambda x: reduce(lambda acc, f: f(acc), reversed(funcs), x) def add_one(x): return x + 1 def square(x): return x * x def multiply_by_two(x): return x * 2 composed = compose(square, multiply_by_two, add_one) # Order is correct result = composed(5) # ((5 + 1) * 2)^2 = 144 print("Composed result:", result)

Enter fullscreen mode Exit fullscreen mode

The Python snippet defines a compose function that takes a variable number of functions (*funcs) as arguments. It returns a new function (a lambda) that takes an initial value x. Inside the lambda, it uses reduce to apply the functions in sequence. The trick here is reversed(funcs). reduce normally applies functions from left to right, but in function composition, we usually want the rightmost function to be applied first. reversed(funcs) reverses the order of functions, so reduce effectively applies them from right to left. The functions add_one, square, multiply_by_two demonstrates what functions can be composed. The order matters in composition. The comment ((5 + 1) * 2)^2 = 144 shows how the functions are applied step by step, starting with add_one.

JavaScript

<span>const</span> <span>compose</span> <span>=</span> <span>(...</span><span>funcs</span><span>)</span> <span>=></span> <span>x</span> <span>=></span> <span>funcs</span><span>.</span><span>reduceRight</span><span>((</span><span>acc</span><span>,</span> <span>f</span><span>)</span> <span>=></span> <span>f</span><span>(</span><span>acc</span><span>),</span> <span>x</span><span>);</span>
<span>const</span> <span>addOne</span> <span>=</span> <span>x</span> <span>=></span> <span>x</span> <span>+</span> <span>1</span><span>;</span>
<span>const</span> <span>square</span> <span>=</span> <span>x</span> <span>=></span> <span>x</span> <span>*</span> <span>x</span><span>;</span>
<span>const</span> <span>multiplyByTwo</span> <span>=</span> <span>x</span> <span>=></span> <span>x</span> <span>*</span> <span>2</span><span>;</span>
<span>const</span> <span>composed</span> <span>=</span> <span>compose</span><span>(</span><span>square</span><span>,</span> <span>multiplyByTwo</span><span>,</span> <span>addOne</span><span>);</span> <span>// Order is correct</span>
<span>const</span> <span>result</span> <span>=</span> <span>composed</span><span>(</span><span>5</span><span>);</span> <span>// ((5 + 1) * 2)^2 = 144</span>
<span>console</span><span>.</span><span>log</span><span>(</span><span>"</span><span>Composed result:</span><span>"</span><span>,</span> <span>result</span><span>);</span>
<span>const</span> <span>compose</span> <span>=</span> <span>(...</span><span>funcs</span><span>)</span> <span>=></span> <span>x</span> <span>=></span> <span>funcs</span><span>.</span><span>reduceRight</span><span>((</span><span>acc</span><span>,</span> <span>f</span><span>)</span> <span>=></span> <span>f</span><span>(</span><span>acc</span><span>),</span> <span>x</span><span>);</span>

<span>const</span> <span>addOne</span> <span>=</span> <span>x</span> <span>=></span> <span>x</span> <span>+</span> <span>1</span><span>;</span>
<span>const</span> <span>square</span> <span>=</span> <span>x</span> <span>=></span> <span>x</span> <span>*</span> <span>x</span><span>;</span>
<span>const</span> <span>multiplyByTwo</span> <span>=</span> <span>x</span> <span>=></span> <span>x</span> <span>*</span> <span>2</span><span>;</span>

<span>const</span> <span>composed</span> <span>=</span> <span>compose</span><span>(</span><span>square</span><span>,</span> <span>multiplyByTwo</span><span>,</span> <span>addOne</span><span>);</span> <span>// Order is correct</span>
<span>const</span> <span>result</span> <span>=</span> <span>composed</span><span>(</span><span>5</span><span>);</span> <span>// ((5 + 1) * 2)^2 = 144</span>
<span>console</span><span>.</span><span>log</span><span>(</span><span>"</span><span>Composed result:</span><span>"</span><span>,</span> <span>result</span><span>);</span>
const compose = (...funcs) => x => funcs.reduceRight((acc, f) => f(acc), x); const addOne = x => x + 1; const square = x => x * x; const multiplyByTwo = x => x * 2; const composed = compose(square, multiplyByTwo, addOne); // Order is correct const result = composed(5); // ((5 + 1) * 2)^2 = 144 console.log("Composed result:", result);

Enter fullscreen mode Exit fullscreen mode

The JavaScript snippet defines a compose function using arrow function syntax. It’s very concise. ...funcs collects all function arguments into an array. The returned function takes an initial value x and uses funcs.reduceRight((acc, f) => f(acc), x). The reduceRight method is the key here; it’s a built-in array method that applies a function against an accumulator and each element of the array (from right to left), reducing it to a single value. This achieves the correct order of function application directly, without needing to reverse the function list like in Python.

Go

<span>package</span> <span>main</span>
<span>import</span> <span>"fmt"</span>
<span>func</span> <span>compose</span><span>[</span><span>T</span> <span>any</span><span>](</span><span>funcs</span> <span>...</span><span>func</span><span>(</span><span>T</span><span>)</span> <span>T</span><span>)</span> <span>func</span><span>(</span><span>T</span><span>)</span> <span>T</span> <span>{</span>
<span>return</span> <span>func</span><span>(</span><span>x</span> <span>T</span><span>)</span> <span>T</span> <span>{</span>
<span>result</span> <span>:=</span> <span>x</span>
<span>for</span> <span>_</span><span>,</span> <span>f</span> <span>:=</span> <span>range</span> <span>funcs</span> <span>{</span>
<span>result</span> <span>=</span> <span>f</span><span>(</span><span>result</span><span>)</span>
<span>}</span>
<span>return</span> <span>result</span>
<span>}</span>
<span>}</span>
<span>func</span> <span>addOne</span><span>(</span><span>x</span> <span>int</span><span>)</span> <span>int</span> <span>{</span>
<span>return</span> <span>x</span> <span>+</span> <span>1</span>
<span>}</span>
<span>func</span> <span>square</span><span>(</span><span>x</span> <span>int</span><span>)</span> <span>int</span> <span>{</span>
<span>return</span> <span>x</span> <span>*</span> <span>x</span>
<span>}</span>
<span>func</span> <span>multiplyByTwo</span><span>(</span><span>x</span> <span>int</span><span>)</span> <span>int</span> <span>{</span>
<span>return</span> <span>x</span> <span>*</span> <span>2</span>
<span>}</span>
<span>func</span> <span>main</span><span>()</span> <span>{</span>
<span>composed</span> <span>:=</span> <span>compose</span><span>(</span><span>addOne</span><span>,</span> <span>multiplyByTwo</span><span>,</span> <span>square</span><span>)</span>
<span>result</span> <span>:=</span> <span>composed</span><span>(</span><span>5</span><span>)</span> <span>// ((5 + 1) * 2)^2 = 144</span>
<span>fmt</span><span>.</span><span>Println</span><span>(</span><span>"Composed result:"</span><span>,</span> <span>result</span><span>)</span>
<span>}</span>
<span>package</span> <span>main</span>

<span>import</span> <span>"fmt"</span>

<span>func</span> <span>compose</span><span>[</span><span>T</span> <span>any</span><span>](</span><span>funcs</span> <span>...</span><span>func</span><span>(</span><span>T</span><span>)</span> <span>T</span><span>)</span> <span>func</span><span>(</span><span>T</span><span>)</span> <span>T</span> <span>{</span>
    <span>return</span> <span>func</span><span>(</span><span>x</span> <span>T</span><span>)</span> <span>T</span> <span>{</span>
        <span>result</span> <span>:=</span> <span>x</span>
        <span>for</span> <span>_</span><span>,</span> <span>f</span> <span>:=</span> <span>range</span> <span>funcs</span> <span>{</span>
            <span>result</span> <span>=</span> <span>f</span><span>(</span><span>result</span><span>)</span>
        <span>}</span>
        <span>return</span> <span>result</span>
    <span>}</span>
<span>}</span>

<span>func</span> <span>addOne</span><span>(</span><span>x</span> <span>int</span><span>)</span> <span>int</span> <span>{</span>
    <span>return</span> <span>x</span> <span>+</span> <span>1</span>
<span>}</span>

<span>func</span> <span>square</span><span>(</span><span>x</span> <span>int</span><span>)</span> <span>int</span> <span>{</span>
    <span>return</span> <span>x</span> <span>*</span> <span>x</span>
<span>}</span>

<span>func</span> <span>multiplyByTwo</span><span>(</span><span>x</span> <span>int</span><span>)</span> <span>int</span> <span>{</span>
    <span>return</span> <span>x</span> <span>*</span> <span>2</span>
<span>}</span>

<span>func</span> <span>main</span><span>()</span> <span>{</span>
    <span>composed</span> <span>:=</span> <span>compose</span><span>(</span><span>addOne</span><span>,</span> <span>multiplyByTwo</span><span>,</span> <span>square</span><span>)</span>
    <span>result</span> <span>:=</span> <span>composed</span><span>(</span><span>5</span><span>)</span> <span>// ((5 + 1) * 2)^2 = 144</span>
    <span>fmt</span><span>.</span><span>Println</span><span>(</span><span>"Composed result:"</span><span>,</span> <span>result</span><span>)</span>
<span>}</span>
package main import "fmt" func compose[T any](funcs ...func(T) T) func(T) T { return func(x T) T { result := x for _, f := range funcs { result = f(result) } return result } } func addOne(x int) int { return x + 1 } func square(x int) int { return x * x } func multiplyByTwo(x int) int { return x * 2 } func main() { composed := compose(addOne, multiplyByTwo, square) result := composed(5) // ((5 + 1) * 2)^2 = 144 fmt.Println("Composed result:", result) }

Enter fullscreen mode Exit fullscreen mode

The go snippet defines a compose function takes advantage of Go 1.18+ generics.
It is defined to take a variadic number of functions (funcs ...func(T) T). The T represents any data type. The key difference is in how the functions are applied. It uses a simple for...range loop to iterate through the funcs slice in the order they were provided. Unlike Python and JavaScript, this Go compose function applies functions from left to right. This is a deliberate choice to make the code simpler, and in the provided main() function, this is accounted for. The composed variable receives the composition, but the functions are listed in the reverse order (addOne, multiplyByTwo, square) compared to what would be mathematically expected. The final call to composed(5) produces correct results.

Conclusion

Each of these three languages brings its own unique approach to functional programming. Python and JavaScript, with their dynamic typing and built-in support for many functional features, offer a relatively lower barrier to entry. Go, on the other hand, while requiring a bit more effort to implement some functional concepts, provides strong immutability support and explicitness, which can be advantageous in certain scenarios.

Subscribe for More!

If you enjoyed this comparison, be sure to subscribe to my YouTube channel for more content on programming languages, software development, and other tech topics.

Let me know in the comments which language you prefer for functional programming and why!

Let’s Talk Dev – YouTube

I share my insights and tips on software engineering topics such as web development, databases, cloud computing, and more. Hi, I’m Mihai and I’m a full-stack software engineer with a passion for creating innovative and user-friendly solutions using web and cloud technologies. I have a home lab where I like to experiment with Kubernetes and other cutting-edge technologies. I’m also a big fan of open-source software. When I’m not coding, I enjoy photography, reading books, learning about finance and entrepreneurship, and watching movies.

youtube.com

About me

I’m Mihai Farcas, a software engineer with a few years of experience under my belt. I’m passionate about writing code and love sharing knowledge with fellow developers.

My YouTube channel, “Let’s Talk Dev,” is where I break down complex concepts, share my experiences (both the good and the face-palm moments).

Connect with me:

Website: https://mihai.ltd
YouTube: https://www.youtube.com/@letstalkdev
GitHub: https://github.com/mihailtd
LinkedIn: https://www.linkedin.com/in/mihai-farcas-ltd/

原文链接:Functional Programming Face-Off: Python vs JavaScript vs Go!

© 版权声明
THE END
喜欢就支持一下吧
点赞6 分享
People are not just to love and live.
人不是仅仅为了爱而生存的
评论 抢沙发

请登录后发表评论

    暂无评论内容