# Functional Programming Concepts in Dart: A Comprehensive Guide

While Dart is primarily an object-oriented language, it also supports many functional programming concepts. This guide covers key functional programming features in Dart.

## 1. Higher-Order Functions

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

### Example:

```dart
void main() {
  var numbers = [1, 2, 3, 4, 5];
  
  // Using a higher-order function (map)
  var doubled = numbers.map((n) => n * 2);
  print(doubled); // (2, 4, 6, 8, 10)

  // Creating a higher-order function
  Function multiplyBy(int factor) {
    return (int number) => number * factor;
  }

  var tripler = multiplyBy(3);
  print(tripler(4)); // 12
}
```

## 2. Closures

Closures are functions that have access to variables in their lexical scope, even when the function is used outside of its original scope.

### Example:

```dart
Function counter() {
  int count = 0;
  return () {
    count++;
    return count;
  };
}

void main() {
  var increment = counter();
  print(increment()); // 1
  print(increment()); // 2
  print(increment()); // 3
}
```

## 3. Pure Functions

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

### Example:

```dart
// Pure function
int add(int a, int b) {
  return a + b;
}

// Impure function (has side effect)
int currentCount = 0;
int incrementAndAdd(int value) {
  currentCount++;
  return currentCount + value;
}

void main() {
  print(add(3, 4)); // Always 7
  print(incrementAndAdd(3)); // 4
  print(incrementAndAdd(3)); // 5
}
```

## 4. Immutability

Immutability involves working with unchangeable data. Dart supports this through `final` and `const` keywords.

### Example:

```dart
void main() {
  final list = [1, 2, 3];
  // list = [4, 5, 6]; // Error: Can't assign to final variable
  list.add(4); // OK, but modifies the list

  const constList = [1, 2, 3];
  // constList.add(4); // Error: Can't modify a const list

  // Creating a new list instead of modifying
  final newList = [...list, 5];
  print(newList); // [1, 2, 3, 4, 5]
}
```

## 5. Recursion

Recursion is a technique where a function calls itself to solve a problem.

### Example:

```dart
int factorial(int n) {
  if (n <= 1) return 1;
  return n * factorial(n - 1);
}

void main() {
  print(factorial(5)); // 120
}
```

## 6. Function Composition

Function composition involves creating a new function by combining other functions.

### Example:

```dart
Function compose(Function f, Function g) {
  return (x) => f(g(x));
}

int square(int x) => x * x;
int addOne(int x) => x + 1;

void main() {
  var squareThenAddOne = compose(addOne, square);
  var addOneThenSquare = compose(square, addOne);

  print(squareThenAddOne(3)); // 10
  print(addOneThenSquare(3)); // 16
}
```

## Conclusion

While Dart is not a purely functional language, it provides many features that support functional programming paradigms. Understanding and using these concepts can lead to more concise, maintainable, and testable code.