Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
151 changes: 0 additions & 151 deletions docs/combinators.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,93 +35,6 @@ $empty = $io->filter(fn($x) => $x < 40);
$result = $empty->unsafeRun(); // throws NoSuchElementException
```

## Sequence and Traverse

These combinators help you work with collections of effects.

### Sequence

`sequence` transforms a collection of effects into an effect of a collection:

```php
use function Phunkie\Effect\Functions\io\io;

$ios = [
io(function() { return 1; }),
io(function() { return 2; }),
io(function() { return 3; })
];

$result = sequence($ios)->unsafeRun(); // [1, 2, 3]
```

### Traverse

`traverse` is like `sequence` but allows you to transform each value before sequencing:

```php
use function Phunkie\Effect\Functions\io\io;

$numbers = [1, 2, 3];

$result = traverse($numbers, fn($n) =>
io(function() use ($n) {
return $n * 2;
})
)->unsafeRun(); // [2, 4, 6]
```

## Race and Timeout

These combinators help you handle concurrent operations and timeouts.

### Race

`race` runs two effects concurrently and returns the result of the first one to complete:

```php
use function Phunkie\Effect\Functions\io\io;
use function Phunkie\Effect\Functions\blocking\blocking;

$fast = io(function() {
return blocking(function() {
usleep(100000); // 0.1 seconds
return "fast";
});
});

$slow = io(function() {
return blocking(function() {
usleep(200000); // 0.2 seconds
return "slow";
});
});

$result = $fast->race($slow)->unsafeRun(); // "fast"
```

### Timeout

`timeout` adds a timeout to an effect, failing if it takes too long:

```php
use function Phunkie\Effect\Functions\io\io;
use function Phunkie\Effect\Functions\blocking\blocking;

$slow = io(function() {
return blocking(function() {
sleep(2);
return "done";
});
});

try {
$result = $slow->timeout(1000)->unsafeRun(); // throws TimeoutException
} catch (\Exception $e) {
// Handle timeout
}
```

## Error Handling

Combinators also provide ways to handle errors in effects.
Expand Down Expand Up @@ -195,67 +108,3 @@ $message = $result->fold(fn($error) => $error->getMessage())(fn($value) => "ok:
$result = $value * 2;
```

2. **Use Sequence for Collections**
```php
// Good: Using sequence for collections
$results = sequence($ios)->unsafeRun();

// Bad: Manual sequencing
$results = [];
foreach ($ios as $io) {
$results[] = $io->unsafeRun();
}
```

3. **Use Race for Concurrent Operations**
```php
// Good: Using race for concurrent operations
$result = $operation1->race($operation2)->unsafeRun();

// Bad: Manual concurrent execution
$handle1 = $operation1->unsafeRun();
$handle2 = $operation2->unsafeRun();
$result = $handle1->await(); // Might wait unnecessarily
```

4. **Use Timeout for Long-Running Operations**
```php
// Good: Using timeout for long-running operations
$result = $operation->timeout(1000)->unsafeRun();

// Bad: No timeout
$result = $operation->unsafeRun(); // Might hang indefinitely
```

5. **Use Error Handling Combinators**
```php
// Good: Using error handling combinators
$result = $risky->handleError(fn($e) => "fallback")->unsafeRun();

// Bad: Try-catch blocks
try {
$result = $risky->unsafeRun();
} catch (\Exception $e) {
$result = "fallback";
}
```

Remember that combinators are designed to work together. You can chain them to create complex effect compositions:

```php
$result = $io
->map(fn($x) => $x * 2)
->filter(fn($x) => $x > 10)
->timeout(1000)
->handleError(fn($e) => 0)
->unsafeRun();
```

This composition:
1. Doubles the value
2. Filters out values less than 10
3. Times out after 1 second
4. Returns 0 if any error occurs
5. Executes the entire chain

The power of combinators lies in their ability to compose effects in a declarative way, making your code more readable and maintainable.
145 changes: 0 additions & 145 deletions docs/concurrency.md
Original file line number Diff line number Diff line change
Expand Up @@ -207,130 +207,11 @@ Remember that parallel execution is not a silver bullet. Consider:

When in doubt, prefer simpler concurrency models like fibers for I/O operations and only use parallel execution for CPU-intensive tasks that benefit from true parallelism.

## Sequence and Traverse

These combinators help you work with collections of effects:

### Sequence
```php
use function Phunkie\Effect\Functions\io\io;

$ios = [
io(function() { return 1; }),
io(function() { return 2; }),
io(function() { return 3; })
];

$result = sequence($ios)->unsafeRun(); // [1, 2, 3]
```

### Traverse
```php
use function Phunkie\Effect\Functions\io\io;

$numbers = [1, 2, 3];

$result = traverse($numbers, fn($n) =>
io(function() use ($n) {
return $n * 2;
})
)->unsafeRun(); // [2, 4, 6]
```

## Race, Both, Either

These combinators help you handle concurrent operations in different ways:

### Race
```php
$fast = io(function() {
return blocking(function() {
usleep(100000); // 0.1 seconds
return "fast";
});
});

$slow = io(function() {
return blocking(function() {
usleep(200000); // 0.2 seconds
return "slow";
});
});

$result = $fast->race($slow)->unsafeRun(); // "fast"
```

### Both
```php
$result = $operation1->both($operation2)->unsafeRun();
// Returns [result1, result2]
```

### Either
```php
$result = $operation1->either($operation2)->unsafeRun();
// Returns Left(result1) or Right(result2)
```

## Cancellation

Cancellation allows you to stop operations that are no longer needed:

```php
$operation = io(function() {
return blocking(function() {
sleep(10);
return "done";
});
});

$handle = $operation->unsafeRun();
// ... some time later ...
$handle->cancel();
```

## Delay

Delay allows you to schedule operations to run after a specified time:

```php
$operation = io(function() {
return blocking(function() {
return "delayed";
});
});

$result = $operation->delay(1000)->unsafeRun(); // Runs after 1 second
```

## Channels

Channels provide a way to communicate between concurrent operations:

```php
$channel = new Channel();

$producer = io(function() use ($channel) {
return blocking(function() use ($channel) {
$channel->send("message");
});
});

$consumer = io(function() use ($channel) {
return blocking(function() use ($channel) {
return $channel->receive();
});
});

$result = $producer->both($consumer)->unsafeRun();
```

## Best Practices

1. **Choose the Right Execution Context**
- Use Fiber context for I/O operations
- Use Parallel context for CPU-intensive tasks
- Use Process context for isolated operations

2. **Handle Resources Properly**
```php
Expand All @@ -350,29 +231,3 @@ $result = $producer->both($consumer)->unsafeRun();
$result = $operation1->flatMap(fn($a) => $operation2->map(fn($b) => $a + $b));
```

4. **Handle Cancellation**
```php
$handle = $operation->unsafeRun();
try {
$result = $handle->await();
} catch (CancellationException $e) {
// Handle cancellation
}
```

5. **Use Error Handling**
```php
$result = $operation
->handleError(fn($e) => "fallback")
->timeout(1000)
->unsafeRun();
```

Remember that concurrency is a powerful tool, but it comes with complexity. Always consider:
- Resource management
- Error handling
- Cancellation
- Timeouts
- State management

The key is to use the right tool for the job and handle all edge cases appropriately.
10 changes: 1 addition & 9 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,18 +49,10 @@ Master the fundamental building blocks:
- Blockers
- Execution Context
- Parallel Execution
- Sequence and Traverse
- Race, Both, Either
- Cancellation
- Delay
- Channels

### 6. [Resources](resources.md)
- Brackets
- Resource Combinators
- Files
- URL
- Database
- Files, database and network connections

## Contributing

Expand Down
16 changes: 1 addition & 15 deletions docs/io.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,20 +131,6 @@ $workflow = readConfig('config.json')
->flatMap(fn($users) => sendEmails($users));
```

### productR (*>) - Sequence and Discard First

```php
// Run both effects, keep only the second result
$program = writeLog('Starting...')
->productR(performOperation())
->productR(writeLog('Done'));

// Equivalent to:
$program = writeLog('Starting...')
->flatMap(fn($_) => performOperation())
->flatMap(fn($result) => writeLog('Done')->map(fn($_) => $result));
```

## Combining IO

### Sequential Composition
Expand Down Expand Up @@ -318,7 +304,7 @@ plain `for { $x <- io } yield ...` (no guard) works as usual, desugaring to
$program = fetchFromApi()
->flatMap(fn($data) => io(fn() => processData($data)))
->handleErrorWith(fn($error) => io(fn() => logError($error))
->productR(io(fn() => getDefaultData())));
->flatMap(fn() => io(fn() => getDefaultData())));
```

## Running IO
Expand Down
Loading
Loading