Skip to content

Commit

Permalink
Add SumTypes Examples
Browse files Browse the repository at this point in the history
  • Loading branch information
davideme committed Jan 7, 2024
1 parent 39046d7 commit c48420c
Show file tree
Hide file tree
Showing 7 changed files with 179 additions and 11 deletions.
52 changes: 42 additions & 10 deletions FunctionalProgramming.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,44 @@
# Functional programming

| Language/Paradigm | Higher-order functions | Currying | Pure functions | Tail recursion |
| ----------------- | ---------------------- | ----------------------- | -------------- | -------------- |
| JavaScript | X | via anonymous functions | | |
| Python | X | via anonymous functions | | |
| Typescript | X | via anonymous functions | | |
| Java | X | via anonymous functions | | |
| C# | X | via anonymous functions | | |
| C++ | X | via anonymous functions | | X |
| PHP | X | via anonymous functions | | |
| Go | X | via anonymous functions | | |
## higher-order functions

| Language/Paradigm | Higher-order functions | Currying |
| ----------------- | ---------------------- | ----------------------- |
| JavaScript || via anonymous functions |
| Python || via anonymous functions |
| Typescript || via anonymous functions |
| Java || via anonymous functions |
| C# || via anonymous functions |
| C++ || via anonymous functions |
| PHP || via anonymous functions |
| Go || via anonymous functions |

## Pure functions

None of these languages support Pure functions


## Recursion
| Language/Paradigm | Tail recursion | folds | unfolds |
| ----------------- | -------------- | ------------------------------------------ | ------- |
| JavaScript || .reduce() method on arrays ||
| Python || functools.reduce() function on iterables ||
| Typescript || .reduce() method on arrays ||
| Java || .reduce() method on streamable collections ||
| C# || .Aggregate() method on collections ||
| C++ || std::accumulate on sequences. ||
| PHP || array_reduce() on array ||
| Go ||||


## Type systems
| Language/Paradigm | Product types | sum types | Pattern Matching |
| ----------------- | ------------- | ------------------------------ | --------------------------------- |
| JavaScript | |||
| Python | | ✅since 3.5 with typing.Union | ✅since 3.10 with match statement |
| Typescript | | ✅discriminated unions | switch-case with shared field. |
| Java | | Simulated via Sealed Interface | since Java 21 |
| C# | | Simulated via Sealed Class | since C# 9.0 |
| C++ | | since C++17 with std::variant | since C++17 with std::visit |
| PHP | |||
| Go | |||
35 changes: 35 additions & 0 deletions c++/Typing discipline/SumTypes/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#include <iostream>
#include <memory>
#include <variant>

class Empty {};

class Node;

using LinkedList = std::variant<std::shared_ptr<Node>, Empty>;

class Node {
public:
int value;
LinkedList next;

Node(int val, LinkedList nxt) : value(val), next(nxt) {}
};

void processList(const LinkedList& list) {
std::visit([](auto&& arg) {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, std::shared_ptr<Node>>) {
std::cout << "Node with value: " << arg->value << std::endl;
processList(arg->next);
} else {
std::cout << "End of list" << std::endl;
}
}, list);
}

int main() {
LinkedList myList = std::make_shared<Node>(1, std::make_shared<Node>(2, std::make_shared<Node>(3, Empty())));
processList(myList);
return 0;
}
24 changes: 24 additions & 0 deletions c-sharp/Functional Programming/SumTypes/Main.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
public abstract record LinkedList();

public sealed record Node(int Value, LinkedList Next) : LinkedList;

public sealed record Empty() : LinkedList;

public class Program {
public static void ProcessList(LinkedList list) {
switch (list) {
case Node node:
Console.WriteLine($"Node with value: {node.Value}");
ProcessList(node.Next);
break;
case Empty:
Console.WriteLine("End of list");
break;
}
}

public static void Main() {
LinkedList myList = new Node(1, new Node(2, new Node(3, new Empty())));
ProcessList(myList);
}
}
22 changes: 22 additions & 0 deletions java/Functional Programming/SumTypes/Main.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
public sealed interface LinkedList permits Node, Empty {}

public record Node(int value, LinkedList next) implements LinkedList {}

public final class Empty implements LinkedList {}

public class Main {
public static void processList(LinkedList list) {
switch (list) {
case Node node -> {
System.out.println("Node with value: " + node.value());
processList(node.next());
}
case Empty empty -> System.out.println("End of list");
}
}

public static void main(String[] args) {
LinkedList myList = new Node(1, new Node(2, new Node(3, new Empty())));
processList(myList);
}
}
24 changes: 24 additions & 0 deletions python/Functional Programming/SumTypes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from dataclasses import dataclass

@dataclass
class Node:
value: int
next: 'LinkedList'

@dataclass
class Empty:
pass

# Using the union operator to define the LinkedList type
LinkedList = Node | Empty

def process_list(lst: LinkedList):
match lst:
case Node(value, next):
print(f"Node with value: {value}")
process_list(next)
case Empty():
print("End of list")

my_list = Node(1, Node(2, Node(3, Empty())))
process_list(my_list)
4 changes: 3 additions & 1 deletion typescript/Functional Programming/Currying.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
function add(a: number): (number) => number {
(() => {
function add(a: number): (number) => number {
return function(b: number): number {
return a + b;
};
}

const addFive = add(5);
console.log(addFive(3)); // 8
})()
29 changes: 29 additions & 0 deletions typescript/Functional Programming/SumTypes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
(() => {
type LinkedList = Node | Empty;

class Node {
kind: "Node" = "Node";
constructor(public value: number, public next: LinkedList) {}
}

class Empty {
kind: "Empty" = "Empty";
}

function processList(list: LinkedList): void {
switch (list.kind) {
case "Node":
console.log(`Node with value: ${list.value}`);
processList(list.next);
break;
case "Empty":
console.log("End of list");
break;
}
}

// Example usage
const myList: LinkedList = new Node(1, new Node(2, new Node(3, new Empty())));
processList(myList);

})()

0 comments on commit c48420c

Please sign in to comment.