Skip to content

Commit fdb7f85

Browse files
committed
added missing documentation for applicative validation
1 parent 538c517 commit fdb7f85

3 files changed

Lines changed: 170 additions & 0 deletions

File tree

README.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,56 @@ var result = "hello"
291291
.Do(s => $"{s}!"); // "HELLO!"
292292
```
293293

294+
### Currying
295+
296+
Transform multi-parameter functions into chains of single-parameter functions:
297+
298+
```csharp
299+
Func<int, int, int> add = (a, b) => a + b;
300+
var curriedAdd = add.Curry(); // Func<int, Func<int, int>>
301+
302+
var addFive = curriedAdd(5); // Func<int, int>
303+
var result = addFive(3); // 8
304+
```
305+
306+
### Partial application
307+
308+
Apply arguments one at a time, reducing arity at each step:
309+
310+
```csharp
311+
Func<string, int, string> repeat = (s, n) => string.Concat(Enumerable.Repeat(s, n));
312+
var repeatHello = repeat.Apply("hello "); // Func<int, string>
313+
var result = repeatHello(3); // "hello hello hello "
314+
```
315+
316+
### Function composition
317+
318+
Combine functions into pipelines with `ComposeLeft` (left-to-right) and `ComposeRight` (right-to-left):
319+
320+
```csharp
321+
Func<string, int> parse = int.Parse;
322+
Func<int, string> format = n => $"Number: {n}";
323+
324+
var pipeline = parse.ComposeLeft(format); // Func<string, string>
325+
var result = pipeline("42"); // "Number: 42"
326+
```
327+
328+
### Applicative validation
329+
330+
Accumulate all errors instead of short-circuiting on the first failure:
331+
332+
```csharp
333+
// Apply — short-circuits on first failure (monadic)
334+
success<Func<string, int, User>, ValidationException>(createUser)
335+
.Apply(ValidateName(input)) // fails → stops
336+
.Apply(ValidateAge(input)); // never checked
337+
338+
// Validate — collects ALL failures (applicative)
339+
success<Func<string, int, User>, ValidationException>(createUser)
340+
.Validate(ValidateName(input)) // fails → keeps going
341+
.Validate(ValidateAge(input)); // also checked → both errors merged
342+
```
343+
294344
## Documentation
295345

296346
For full API documentation, visit the [**Funk documentation site**](https://hcerim.github.io/Funk).

docs/extensions.markdown

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,3 +243,73 @@ Other notable operations include:
243243
- `Match` — pattern-matches on the sequence based on its count (empty, single, multiple)
244244

245245
These operations work together with the Funk types to enable fully functional pipelines over collections — no statements, no null checks, no surprises.
246+
247+
## Boolean extensions
248+
249+
Funk provides pattern matching and lifting for boolean values.
250+
251+
`Match` on booleans provides a concise way to branch on `true` and `false` without `if-else` statements.
252+
253+
```c#
254+
var label = isActive.Match(
255+
_ => "Inactive",
256+
_ => "Active"
257+
); // string
258+
```
259+
260+
`AsTrue` lifts a boolean into a `Maybe<bool>`. If the value is `true`, it returns a non-empty `Maybe`. If `false` (or `null` for nullable booleans), it returns an empty `Maybe`. This enables integration with the rest of the `Maybe` pipeline.
261+
262+
```c#
263+
var authorized = user.IsAdmin.AsTrue()
264+
.Map(_ => LoadAdminPanel()); // Maybe<Panel> — empty if not admin
265+
266+
bool? consent = null;
267+
var hasConsent = consent.AsTrue(); // Maybe<bool> — empty
268+
```
269+
270+
Logical combinators `And` and `Or` provide fluent, lazy boolean composition.
271+
272+
```c#
273+
var allowed = user.IsAdmin.Or(_ => user.HasPermission("write")); // lazy — second check only if first is false
274+
var valid = input.NotEmpty.And(_ => input.IsWellFormed); // lazy — second check only if first is true
275+
```
276+
277+
## Exc extensions
278+
279+
Beyond the core `Exc` operations documented in [Exc](/Funk/types/exc/), Funk provides additional extension methods.
280+
281+
### AsSuccess
282+
283+
Converts an `Exc` to a `Maybe`, keeping only the success value. Failure and empty states both become an empty `Maybe`.
284+
285+
```c#
286+
var result = Exc.Create<int, FormatException>(_ => int.Parse("42"));
287+
var maybe = result.AsSuccess(); // Maybe<int> — 42
288+
```
289+
290+
### Flatten
291+
292+
Flattens a nested `Exc<Exc<T, E>, E>` into a single `Exc<T, E>`.
293+
294+
```c#
295+
Exc<Exc<int, Exception>, Exception> nested = GetNestedResult();
296+
var flat = nested.Flatten(); // Exc<int, Exception>
297+
```
298+
299+
## Applicative functions (Apply and Validate)
300+
301+
Funk provides applicative functor operations for both `Maybe` and `Exc`. These are documented in detail on their respective type pages — see [Maybe applicative](/Funk/types/maybe/#applicative-applicative-functor) and [Exc applicative](/Funk/types/exc/#applicative-applicative-functor).
302+
303+
In summary:
304+
305+
- **`Apply`** (monadic) — short-circuits on the first empty/failed value. Use when later arguments depend on earlier ones.
306+
- **`Validate`** (applicative) — accumulates all errors. Use for validation scenarios where you want to report all problems at once.
307+
308+
```c#
309+
// Validate — accumulates ALL errors
310+
var customer = success<Func<string, int, Customer>, ValidationException>(createCustomer)
311+
.Validate(ValidateName(input))
312+
.Validate(ValidateAge(input)); // collects both errors if both fail
313+
```
314+
315+
`Apply` and `Validate` are available for arities 1 through 5 for both `Func` and `Action` delegates.

docs/index.markdown

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,56 @@ var result = "hello"
290290
.Do(s => $"{s}!"); // "HELLO!"
291291
```
292292

293+
### Currying
294+
295+
Transform multi-parameter functions into chains of single-parameter functions:
296+
297+
```csharp
298+
Func<int, int, int> add = (a, b) => a + b;
299+
var curriedAdd = add.Curry(); // Func<int, Func<int, int>>
300+
301+
var addFive = curriedAdd(5); // Func<int, int>
302+
var result = addFive(3); // 8
303+
```
304+
305+
### Partial application
306+
307+
Apply arguments one at a time, reducing arity at each step:
308+
309+
```csharp
310+
Func<string, int, string> repeat = (s, n) => string.Concat(Enumerable.Repeat(s, n));
311+
var repeatHello = repeat.Apply("hello "); // Func<int, string>
312+
var result = repeatHello(3); // "hello hello hello "
313+
```
314+
315+
### Function composition
316+
317+
Combine functions into pipelines with `ComposeLeft` (left-to-right) and `ComposeRight` (right-to-left):
318+
319+
```csharp
320+
Func<string, int> parse = int.Parse;
321+
Func<int, string> format = n => $"Number: {n}";
322+
323+
var pipeline = parse.ComposeLeft(format); // Func<string, string>
324+
var result = pipeline("42"); // "Number: 42"
325+
```
326+
327+
### Applicative validation
328+
329+
Accumulate all errors instead of short-circuiting on the first failure:
330+
331+
```csharp
332+
// Apply — short-circuits on first failure (monadic)
333+
success<Func<string, int, User>, ValidationException>(createUser)
334+
.Apply(ValidateName(input)) // fails → stops
335+
.Apply(ValidateAge(input)); // never checked
336+
337+
// Validate — collects ALL failures (applicative)
338+
success<Func<string, int, User>, ValidationException>(createUser)
339+
.Validate(ValidateName(input)) // fails → keeps going
340+
.Validate(ValidateAge(input)); // also checked → both errors merged
341+
```
342+
293343
## Documentation
294344

295345
For full API documentation, visit the [**Funk documentation site**](https://hcerim.github.io/Funk).

0 commit comments

Comments
 (0)