Jump to content

Functional Programming: Difference between revisions

From Knowledge Base
Created page with "== Functional Programming == Functional programming in C# can complement both imperative and object-oriented programming paradigms. Let's get started with functional programming in C#: === Delegates === C# provides delegates and events, which are critical for functional programming - these include `Action` and `Func`. === Action Delegate in C#: === The `Action` delegate is a predefined delegate type in C# that represents a method which performs an action and does not r..."
 
No edit summary
Line 7: Line 7:
=== Action Delegate in C#: ===
=== Action Delegate in C#: ===
The `Action` delegate is a predefined delegate type in C# that represents a method which performs an action and does not return a value. It can take parameters, but it does not return any value (it returns `void`).
The `Action` delegate is a predefined delegate type in C# that represents a method which performs an action and does not return a value. It can take parameters, but it does not return any value (it returns `void`).
<source lang="php">
<?php
    v = "string";    // sample initialization
?>
html text
<?php
    echo v;        // end of php code
?>
</source>
<source lang="csharp">
<source lang="csharp">
Action<string> greet = name => Console.WriteLine($"Hello, {name}!");
Action<string> greet = name => Console.WriteLine($"Hello, {name}!");

Revision as of 06:55, 17 January 2025

Functional Programming

Functional programming in C# can complement both imperative and object-oriented programming paradigms. Let's get started with functional programming in C#:

Delegates

C# provides delegates and events, which are critical for functional programming - these include `Action` and `Func`.

Action Delegate in C#:

The `Action` delegate is a predefined delegate type in C# that represents a method which performs an action and does not return a value. It can take parameters, but it does not return any value (it returns `void`). <source lang="php"> <?php

   v = "string";    // sample initialization

?> html text <?php

   echo v;         // end of php code

?> </source> <source lang="csharp"> Action<string> greet = name => Console.WriteLine($"Hello, {name}!"); greet("World"); // Output: Hello, World! </source>

Func Delegate in C#

The `Func` delegate type represents a method that takes zero or more input parameters and returns a value. The last type parameter specifies the return type. ```csharp Func<int, int, int> sum = (x, y) => x + y; int result = sum(2, 3); // result = 5 Console.WriteLine(result); // Output: 5 ```

Basics

Lambda Expressions

C# provides lambda expressions and closures, which are essential for functional programming. These allow you to define and pass functions as arguments to other functions.

   ```csharp
   Func<int, int> square = x => x * x;
   int result = square(5); // result will be 25
   ```

Immutable Data

Immutable data structures ensure that once a data structure is created, it cannot be modified.

   ```csharp
   public class ImmutablePerson
   {
       public readonly string Name;
       public readonly int Age;
   
       public ImmutablePerson(string name, int age)
       {
           Name = name;
           Age = age;
       }
   }
   ```
  In functional programming, immutability is a core concept that helps to avoid side effects and maintain a clear flow of data through functions.

LINQ

LINQ is a powerful feature in C# that enables functional-style querying of collections.

Higher-Order Functions

Higher-order functions are functions that can take other functions as parameters or return functions as results.

   ```csharp
   List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
   
   List<int> squareNumbers = numbers.Select(x => x * x).ToList(); // squareNumbers contains [1, 4, 9, 16, 25]
   ```

Pure Functions

Pure functions have no side effects and always return the same output for the same input.

   ```csharp
   int Add(int a, int b)
   {
       return a + b;
   }
   ```

Functional Composition

Functional composition involves combining smaller functions to create more complex ones.

   ```csharp
   Func<int, int> doubleNumber = x => x * 2;
   Func<int, int> squareNumber = x => x * x;
   Func<int, int> compose = x => doubleNumber(squareNumber(x));
   int result = compose(3); // Result: 18 (first square, then double)
   ```

Pattern Matching

Pattern matching in C# allows you to write more expressive and functional code when dealing with complex data structures. It's a valuable feature in functional programming.

   ```csharp
   public record Circle(double Radius);
   public record Rectangle(double Width, double Height);
   public record Triangle(double Base, double Height);
   static double CalculateArea(object shape) => shape switch {
       Circle circle => Math.PI * Math.Pow(circle.Radius, 2),
       Rectangle rectangle => rectangle.Width * rectangle.Height,
       Triangle triangle => 0.5 * triangle.Base * triangle.Height,
       _ => throw new ArgumentException("Unknown shape")
   };
   static void Main() {
       Circle circle = new Circle(5.0);
       Rectangle rectangle = new Rectangle(4.0, 6.0);
       Triangle triangle = new Triangle(3.0, 4.0);
       Console.WriteLine($"Circle area: {CalculateArea(circle)}");  // Circle area: 78.53981633974483
       Console.WriteLine($"Rectangle area: {CalculateArea(rectangle)}");  // Rectangle area: 24
       Console.WriteLine($"Triangle area: {CalculateArea(triangle)}");  // Triangle area: 6
   }
   ```

Monads

Monads encapsulates and abstracts values to enable consistent and controlled manipulation, composition and transformation of those value.

   ```csharp
   int? number = 42;
   int? result = number
       .Select(x => x * 2)
       .Where(x => x > 50)
       .FirstOrDefault();
   Console.WriteLine(result); // Result: 84
   ```

Option Types (Optional Values)

An option type represents values that can be either present or absent (null), providing a safer and more expressive way to handle potentially missing data. Option Types (Handling Optional Values):

   ```csharp
   int? someValue = 42; // A value exists.
   int result = someValue ?? 0; // If someValue is null, use a default value (0).
   ```

There are libraries and frameworks available in C# that can assist you in functional programming, such as LanguageExt and F#.

Concepts

Currying

Currying is the process of converting a function that takes multiple arguments into a series of functions, each taking a single argument. In C#, you can implement currying using lambda expressions: ```csharp Func<int, Func<int, int>> curriedAdd = a => b => a + b; int addTwo = curriedAdd(2); int result = addTwo(3); // result will be 5 ``` In this example, `curriedAdd` is a curried function that takes two integers and returns a new function that adds them. This concept can help with partial function application and creating more reusable functions. ![2023-11-02 12_06_28.png](/.attachments/2023-11-02%2012_06_28-aaba2e8e-3ca1-4016-a1cc-4335c8751289.png)

    1. Partial Function Application

Partial function application is a technique where you fix a certain number of arguments of a function, creating a new function with fewer parameters. In C#, you can achieve this using lambda expressions as well: ```csharp Func<int, int, int> add = (a, b) => a + b; Func<int, int> addTwo = a => add(a, 2); int result = addTwo(3); // result will be 5 ``` Here, `addTwo` partially applies the `add` function by fixing one of its arguments to 2, resulting in a new function that only requires one input.

Memoization

Memoization is a caching technique where the results of expensive function calls are stored and reused when the same inputs occur again. You can implement memoization in C# to optimize recursive or computationally expensive functions, making them more efficient. This demonstrates memoization for Fibonacci numbers using a Dictionary for caching: ```csharp using System; using System.Collections.Generic;

static class MemoizationExample {

   static Dictionary<int, long> memo = new Dictionary<int, long>();
   static long Fibonacci(int n) =>
       n <= 1 ? n : (memo.ContainsKey(n) ? memo[n] : (memo[n] = Fibonacci(n - 1) + Fibonacci(n - 2)));
   static void Main() {
       Console.WriteLine($"Fibonacci(40) = {Fibonacci(40)}");
   }

}

```

Monads

Monads are a fundamental concept in functional programming that provide a way to handle sequences of operations, error handling and side effects in a clean and composable manner. In C#, you can work with monads for tasks like asynchronous programming using Task<T>, error handling using Option or Either types, or working with sequences using LINQ. This Task monad for asynchronous programming uses await with Task.Delay to simulate asynchronous operations and processing. ```csharp using System; using System.Threading.Tasks;

static class MonadExample {

   static async Task Main() {
       int data = await ReadDataAsync();
       int result = await ProcessDataAsync(data);
       Console.WriteLine($"Result: {result}");
   }
   static async Task<int> ReadDataAsync() => await Task.Delay(1000).ContinueWith(_ => 42);
   static async Task<int> ProcessDataAsync(int data) => await Task.Delay(500).ContinueWith(_ => data * 2);

} ```

Recursion

Functional programming encourages the use of recursion for solving problems. Recursion is the process of a function calling itself to solve a problem. Make sure to learn about tail recursion and how to optimize recursive functions in C#. Using recursion to calculate the factorial of a number in C#, without additional functions or set-up: ```csharp using System;

static class RecursionExample {

   static int Factorial(int n) => n == 0 ? 1 : n * Factorial(n - 1);
   static void Main() {
       int n = 5;
       Console.WriteLine($"Factorial({n}) = {Factorial(n)}");
   }

} ```