<commit_before>## Task

A Task is a composable unit of asynchronous work.  You can build a blueprint of asynchronous steps using Task operations like `map` and `chain`, and then run the blueprint using `runTask` to get the Task's result.

Tasks are:

- Lazy: they only execute when their result is demanded with `runTask`.
- Single-consumer: they don't cache their result: they execute and produce a new result each time you pass them to `runTask`.

Running a Task returns a pair: `[killTask, futureValue]`:

- `killTask :: () -> void`: function to abort the Task.  If called before the Task finishes, `futureValue` will remain pending forever.
- `futureValue :: FutureValue a`: a [FutureValue](#futurevalue) representing the Task's result.

## FutureValue

A FutureValue is a value that becomes known at a particular time, for example, when a Task completes.  Once a FutureValue's time and value become known, they are immutable.

In contrast to Tasks, FutureValues are:

- Strict (eager): you don't need to poke a FutureValue for it to receive a value.
- Multi-consumer: they are immutable once set, caching their value and arrival time once known.  You can safely cache FutureValues, give them to multiple consumers, etc.

# API

## Types

`type Resolver a = ((a -> ()) -> Kill`: function to set a Task's result, and return a Kill that can be used to kill the Task while it is still in flight.
`type Kill = { kill :: () -> () }`: Object will a zero-arg `kill` method to kill an in flight Task.
`type KillFunc = () -> ()`: 


## Task

### runTask :: Task a -> [KillFunc, FutureValue a]

Execute a Task.  This forces a Task to execute immediately, returning a `KillFunc` that can be used to abort the Task, and a `FutureValue` representing the Task's eventual result.

### task :: Resolver a &rarr; Task a

Create a Task that will produce a result by running a resolver function.

```js
import { task, killWith } from 'yafi'

const [killTask, futureValue] = task(resolve => {
    return killWith(clearTimeout, setTimeout(resolve, 1000, 'hello world'))
})
```

### map :: Task a ~> (a -> b) -> Task b

Transform a Task's eventual result.

### ap :: Task a ~> Task (a -> b) -> Task b

### lift2 :: (a -> b -> c) -> Task a -> Task b -> Task c

Combine two Tasks to produce a new one.

### chain :: Task a ~> (a -> Task b) -> Task b

Create a new Task by chaining more work onto an existing one.  The provided function takes the original Task's result as input and returns a new Task.

### race :: Task a -> Task a -> Task a

Given two Tasks, return a Task equivalent to the one that produces a result earlier, automatically killing the Task that loses the race.

### killWith :: (a -> ()) -> a -> Kill

Helper to create a Kill instance whose `kill` method calls the provided function with the provided state.

```js
const killTimeout = killWith(clearTimeout, setTimeout(x => console.log(x), 1000, 'Hi!'))

killTimeout() // Hi! is never logged
```

### killBoth :: Kill -> Kill -> Kill

Combine two Kills into one that kills both.

```js
const killTimeout1 = killWith(clearTimeout, setTimeout(x => console.log(x), 1000, 'Hello'))
const killTimeout2 = killWith(clearTimeout, setTimeout(x => console.log(x), 2000, 'World'))

const killTimeouts = killBoth(killTimeout1, killTimeout2)

killTimeouts() // Neither Hello nor World will be logged
```

## FutureValue

### map :: FutureValue a ~> (a -> b) -> FutureValue b

Transform a FutureValue's value, without changing its arrival time.

### earliest :: FutureValue a -> FutureValue a -> FutureValue a

Return a FutureValue that is equivalent to the earlier of two FutureValues
<commit_msg>docs(yafi): Fix markdown, add ap description<commit_after>## Task

A Task is a composable unit of asynchronous work.  You can build a blueprint of asynchronous steps using Task operations like `map` and `chain`, and then run the blueprint using `runTask` to get the Task's result.

Tasks are:

- Lazy: they only execute when their result is demanded with `runTask`.
- Single-consumer: they don't cache their result: they execute and produce a new result each time you pass them to `runTask`.

Running a Task returns a pair: `[killTask, futureValue]`:

- `killTask :: () -> void`: function to abort the Task.  If called before the Task finishes, `futureValue` will remain pending forever.
- `futureValue :: FutureValue a`: FutureValue representing the Task's result.

## FutureValue

A FutureValue is a value that becomes known at a particular time, for example, when a Task completes.  Once a FutureValue's time and value become known, they are immutable.

In contrast to Tasks, FutureValues are:

- Strict (eager): you don't need to poke a FutureValue for it to receive a value.
- Multi-consumer: they are immutable once set, caching their value and arrival time once known.  You can safely cache FutureValues, give them to multiple consumers, etc.

# API

## Types

- `type Resolver a = ((a -> ()) -> Kill`: function to set a Task's result, and return a Kill that can be used to kill the Task while it is still in flight.
- `type Kill = { kill :: () -> () }`: Object will a zero-arg `kill` method to kill an in flight Task.
- `type KillFunc = () -> ()`: 


## Task

### runTask :: Task a -> [KillFunc, FutureValue a]

Execute a Task.  This forces a Task to execute immediately, returning a `KillFunc` that can be used to abort the Task, and a `FutureValue` representing the Task's eventual result.

### task :: Resolver a -> Task a

Create a Task that will produce a result by running a resolver function.

```js
import { task, killWith } from 'yafi'

const [killTask, futureValue] = task(resolve => {
    return killWith(clearTimeout, setTimeout(resolve, 1000, 'hello world'))
})
```

### map :: Task a ~> (a -> b) -> Task b

Transform a Task's eventual result.

### ap :: Task a ~> Task (a -> b) -> Task b

Given a Task that will produce a value and a Task that will produce a function, create a Task that will apply the function to the value and produce the result.

### lift2 :: (a -> b -> c) -> Task a -> Task b -> Task c

Combine two Tasks to produce a new one.

### chain :: Task a ~> (a -> Task b) -> Task b

Create a new Task by chaining more work onto an existing one.  The provided function takes the original Task's result as input and returns a new Task.

### race :: Task a -> Task a -> Task a

Given two Tasks, return a Task equivalent to the one that produces a result earlier, automatically killing the Task that loses the race.

### killWith :: (a -> ()) -> a -> Kill

Helper to create a Kill instance whose `kill` method calls the provided function with the provided state.

```js
const killTimeout = killWith(clearTimeout, setTimeout(x => console.log(x), 1000, 'Hi!'))

killTimeout() // Hi! is never logged
```

### killBoth :: Kill -> Kill -> Kill

Combine two Kills into one that kills both.

```js
const killTimeout1 = killWith(clearTimeout, setTimeout(x => console.log(x), 1000, 'Hello'))
const killTimeout2 = killWith(clearTimeout, setTimeout(x => console.log(x), 2000, 'World'))

const killTimeouts = killBoth(killTimeout1, killTimeout2)

killTimeouts() // Neither Hello nor World will be logged
```

## FutureValue

### map :: FutureValue a ~> (a -> b) -> FutureValue b

Transform a FutureValue's value, without changing its arrival time.

### earliest :: FutureValue a -> FutureValue a -> FutureValue a

Return a FutureValue that is equivalent to the earlier of two FutureValues

{'fraction_non_alphanumeric': 0.10642300456866434, 'fraction_numerical': 0.005643644181671593, 'mean_word_length': 3.919365499008592, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 76, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1235314', 'n_tokens_mistral': 2153, 'n_tokens_neox': 2047, 'n_words': 1060}