Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document moment #66

Merged
merged 1 commit into from
Jul 6, 2019
Merged
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
71 changes: 71 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -682,6 +682,77 @@ occurrence in `source` the function is applied to the current value of
the behaviour and the value of the occurrence, the returned value
becomes the next value of the behavior.

#### `moment<A>(f: (sample: <B>(b: Behavior<B>) => B) => A): Behavior<A>`

Constructs a behavior based on a function. At any point in time the value of
the behavior is equal to the result of applying the function to a sampling
function. The sampling function returns the current value of any behavior.

`moment` is a powerful function that can do many things and sometimes it can do
them in a way that is a lot easier than other functions. A typical usage of
`moment` has the following form.

```js
moment((at) => {
...
})
```

Above, the `at` function above can be applied to any behavior and it will
return the current value of the behavior. The following example adds together
the values of three behaviors of numbers.

```js
const sum = moment((at) => at(aBeh) + at(bBeh) + at(cBeh));
```

The above could also be achieved with `lift`. However, `moment` can give better
performance when used with a function which dynamically switches which
behaviors it depends on. To understand this, consider the following contrived
example.

```js
const lifted = lift((a, b, c, d) => a && b ? c : d, aB, bB, cB, dB);
```

Here the resulting behavior will _always_ depend on both `aB`, `bB`, `cB`,
`dB`. This means that if any of them changes then the value of `lifted` will be
recomputed. But, if for instance, `aB` is `false` then the function actually
only uses `aB` and there is no need to recompute `lifted` if any of the other
behaviors changes. However, `lift` can't know this since the function given to
it is just a "black box".

If, on the other hand, we use `moment`:

```js
const momented = moment((at) => at(aB) && at(bB) ? at(cB) : at(dB));
```

Then `moment` can simply check which behaviors are actually sampled inside the
function passed to it, and it uses this information to figure out which
behaviors `momented` depends upon in any given time. This means that when `aB`
is `false` the implementation can figure out that, currently, `momented` only
depends on `atB` and there is no need to recompute `momented` when any of the
other behaviors changes.

`moment` can also be very useful with behaviors nested inside behaviors. If
`persons` is a behavior of an array of persons and is of the type `Behavior<{
age: Behavior<number>, name: string }[]>` then the following code creates a
behavior that at any time is equal to the name of the first person in the array
whose age is greater than 20.

```js
const first = moment((at) => {
for (const person of at(persons)) {
if (at(person.age) > 20) {
return person.name;
}
}
});
```

Achieving something similar without `moment` would be quite tricky.

#### `time: Behavior<Time>`

A behavior whose value is the number of milliseconds elapsed since UNIX epoch.
Expand Down