{"id":13550726,"url":"https://github.com/funkia/hareactive","last_synced_at":"2025-04-06T05:18:13.078Z","repository":{"id":38898056,"uuid":"60265475","full_name":"funkia/hareactive","owner":"funkia","description":"Purely functional reactive programming library","archived":false,"fork":false,"pushed_at":"2023-01-03T20:42:12.000Z","size":1836,"stargazers_count":337,"open_issues_count":39,"forks_count":29,"subscribers_count":14,"default_branch":"master","last_synced_at":"2025-03-30T04:09:19.363Z","etag":null,"topics":["frp","frp-library","functional-programming","functional-reactive-programming","javascript","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/funkia.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-06-02T13:16:53.000Z","updated_at":"2025-02-11T15:48:40.000Z","dependencies_parsed_at":"2023-02-01T09:46:10.257Z","dependency_job_id":null,"html_url":"https://github.com/funkia/hareactive","commit_stats":null,"previous_names":["paldepind/hareactive"],"tags_count":44,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/funkia%2Fhareactive","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/funkia%2Fhareactive/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/funkia%2Fhareactive/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/funkia%2Fhareactive/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/funkia","download_url":"https://codeload.github.com/funkia/hareactive/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247436455,"owners_count":20938567,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["frp","frp-library","functional-programming","functional-reactive-programming","javascript","typescript"],"created_at":"2024-08-01T12:01:36.719Z","updated_at":"2025-04-06T05:18:13.042Z","avatar_url":"https://github.com/funkia.png","language":"TypeScript","readme":"\u003cimg align=\"right\" width=\"220px\" src=\"https://rawgithub.com/funkia/hareactive/master/logo.svg\"\u003e\n\n[![Build Status](https://travis-ci.org/funkia/hareactive.svg?branch=master)](https://travis-ci.org/funkia/hareactive)\n[![codecov](https://img.shields.io/codecov/c/github/funkia/hareactive.svg)](https://codecov.io/gh/funkia/hareactive)\n[![Gitter](https://img.shields.io/gitter/room/funkia/General.svg)](https://gitter.im/funkia/General)\n\n# Hareactive\n\nHareactive is a purely functional reactive programming (FRP) library\nfor JavaScript and TypeScript. It is simple to use, powerful, and\nperformant.\n\n## Key features\n\n- Simple and precise semantics. This means that everything in the\n  library can be understood based on a very simple mental model. This\n  makes the library easy to use and free from surprises.\n- Purely functional API.\n- Based on classic FRP. This means that the library makes a\n  distinction between behaviors and streams.\n- Supports continuous time for expressive and efficient creation of\n  time-dependent behavior.\n- Integrates with declarative side-effects in a way that is pure,\n  testable and uses FRP for powerful handling of asynchronous\n  operations.\n- Declarative testing. Hareactive programs are easy to test\n  synchronously and declaratively.\n- Great performance.\n\n## Introduction\n\nHareactive is simple. It aims to have an API that is understandable\nand easy to use. It does that by making a clear distinction between\nsemantics and implementation details. This means that the library\nimplements a very simple mental model. By understanding this\nconceptual model the entire API can be understood.\n\nThis means that to you use Hareactive you do not have to worry about\nthings such as \"lazy observables\", \"hot vs cold observables\" and\n\"unicast vs multicast observables\". These are all unfortunate concepts\nthat confuse people and make reactive libraries harder to use. In\nHareactive we consider such things implementation detail that users\nshould never have to think about.\n\nHareactive implements what is called classic FRP. This means that it\nmakes a distinction between two types of time dependent concepts. This\nmakes code written in Hareactive more precise and easier to\nunderstand.\n\nHareactive is powerful. It features all the typical methods found in\nother FRP libraries. But on top of that it comes with many unique\nfeatures that are rarely found elsewhere. For instance, continuous\ntime.\n\n## Table of contents\n\n- [Installation](#installation)\n- [Conceptual overview](#conceptual-overview)\n- [Tutorial/cookbook](#tutorialcookbook)\n- [API documentation](#api)\n- [Contributing](#contributing)\n- [Benchmark](#benchmark)\n\n# Installation\n\nHareactive can be installed from npm. The package ships with both\nCommonJS modules and ES6 modules\n\n```\nnpm install @funkia/hareactive\n```\n\n## Conceptual overview\n\nHareactive contains four key concepts: Behavior, stream, future and\nnow. This section will describe each of these at conceptual level.\n\nFor a practical introduction into using Hareactive see the\n[tutorial](#tutorial). Unless you're already familiar with classic FRP\nyou should at least read the sections on behavior, stream and now\nbefore you dive into the tutorial.\n\n### Behavior\n\nA behavior is a value that changes over time. For instance, the\ncurrent position of the mouse or the value of an input field is a\nbehavior. Conceptually a behavior is a function from a point in time\nto a value. A behavior always has a value at any given time.\n\nSince a behavior is a function of time we can visualize it by plotting\nit as a graph. The figure below shows two examples of behaviors. The\nleft behavior is what we call a _continuous_ behavior since it changes\ninfinitely often. The right behavior only changes at specific moments,\nbut it's still a function of time. Hareactive is implemented so that\nboth types of behavior can be represented efficiently.\n\n![behavior figure](https://rawgit.com/funkia/hareactive/master/figures/behavior.svg)\n\nIt is important to understand that behaviors are not implemented as\nfunctions. Although, in theory, they could be. All operations that\nHareactive offers on behaviors can be explained and defined based on\nthe understanding that a behavior is a function of time. It is a\nmental model that can be used to understand the library.\n\n### Stream\n\nA `Stream` is a series of values that arrive over time. Conceptually\nit is a list of values where each value is associated with a moment in\ntime.\n\nAn example could be a stream of keypresses that a user makes. Each\nkeypress happens at a specific moment in time and with a value\nindicating which key was pressed.\n\nSimilarily to behaviors a stream can be visualized. But, in this case\nwe wont get a graph. Instead we will get some points in time. Each\npoint is called an _occurrence_. The value of an occurrence can be\nanything. For instance, the figure to the left may represent a stream\nof booleans where all the \"low\" stars represents an occurrence with\nthe value `false` and the \"high\" stars represents `true`.\n\n![stream figure](https://rawgit.com/funkia/hareactive/master/figures/stream.svg)\n\nThe difference between a stream and a behavior is pretty clear when we\nsee them visually. A behavior has a value at all points in time where\na stream is a series of events that happens at specific moments in\ntime.\n\nTo understand why Hareactive features both behavior and stream you may\nwant to read the blog post [Behaviors and streams, why\nboth?](http://vindum.io/blog/behaviors-and-streams-why-both/).\n\n### Future\n\nA future is a _value_ associated with a certain point in _time_. For\ninstance, the result of an HTTP-request is a future since it occurs at\na specific time (when the response is received) and contains a value\n(the response itself).\n\nFuture has much in common with JavaScript's Promises. However, it is\nsimpler. A future has no notion of resolution or rejection. That\nis, a specific future can be understood simply as a time and a value.\nConceptually one can think of it as being implemented simply like\nthis.\n\n```js\n{time: 22, value: \"Foo\"}\n```\n\nThe relationship between `Future` and `Stream` is the same as the\nrelationship between having a variable of a type and a variable that\nis a list of that type. You wouldn't store a username as\n`[\"username\"]` because there is always exactly one username.\n\nSimilarly in Hareactive we don't use `Stream` to express the result of\na HTTP-request since a HTTP-request only delivers a response exactly\nonce. It is more precise to use a `Future` for things where there is\nexactly one occurrence and `Stream` where there may be zero or more.\n\n### Future, stream or behavior?\n\nAt first, the difference between the three things may be tricky to\nunderstand. Especially if you're used to other libraries where all\nthree are represented as a single structure (maybe called \"stream\" or\n\"observable\"). The key is to understand that the three types represent\nthings that are fundamentally different. And that expressing different\nthings with different structures is beneficial.\n\nYou could forget about future and use a stream where you'd otherwise\nuse a future. Because stream is more powerful than future. In the same\nway you could always use arrays of values instead of just single\nvalues. But you don't do that because `username = \"foo\"` expresses\nthat only one username exists whereas `username = [\"foo\"]` gives the\nimpression that a user can have more than one username. Similarly one\ncould forget about numbers and just use strings instead. But saying\n`amount = 22` is obviously better than `amount = \"22\"` because it's\nmore precise.\n\nThis is how to figure out if a certain thing is a future, a stream or\na behavior:\n\n1. Ask the question: \"does the thing always have a current value?\". If\n   yes, you're done, the thing should be represented as a behavior.\n2. Ask the question: \"does the thing happen exactly once?\". If yes,\n   the thing should be represented as a future. If no, you should use\n   a stream.\n\nBelow are some examples:\n\n- The time remaining before an alarm goes off: The remaining time\n  always have a current value, therefore it is a behavior.\n- The moment where the alarm goes off: This has no current value. And\n  since the alarm only goes off a single time this is a future.\n- User clicking on a specific button: This has no notion of a current\n  value. And the user may press the button more than once. Thus a\n  stream is the proper representation.\n- Whether or not a button is currently pressed: This always has a\n  current value. The button is always either pressed or not pressed.\n  This should be represented as a behavior.\n- The tenth time a button is pressed: This happens once at a specific\n  moment in time. Use a future.\n\n### Now\n\n`Now` represents a computation that should be run in the present\nmoment. Hence the name \"now\". `Now` is perhaps the most difficult\nconcept in Hareactive.\n\nA value of type `Now` is a _description_ of something that we'd like\nto do. Such a description can declare that it wants to do one of two\nthings.\n\n- Get the current value of behavior. This is done with the `sample`\n  function. Since a `Now`-computation will always be run in the\n  present it is impossible to sample a behavior in the past.\n- Describe side-effects. This is done with functions such as `perform`\n  and `performStream`. With these functions we can describe things\n  that should happen when a stream occurs.\n\nMost Hareactive programs are bootstrapped by a `Now`-computation. That\nis, they take the form.\n\n```js\nconst main = ...\n\nrunNow(main);\n```\n\n`Now` is closely tied to the concept of stateful behaviors which is\nthe topic of the next section.\n\n### How stateful behaviors work\n\nA notorious problem in FRP is how to implement functions that return\nbehaviors or streams that depend on the past. Such behaviors or\nstreams are called \"stateful\"\n\nFor instance `accumFrom` creates a behavior that accumulates values over\ntime. Clearly such a behavior depends on the past. Thus we say that\n`accumFrom` returns a stateful behavior.\n\nImplementing stateful methods such as `accumFrom` in a way that is both\nintuitive to use, pure and memory safe is very tricky.\n\nWhen implementing functions such as `accumFrom` most reactive libraries in\nJavaScript do one of these two things:\n\n- Calling `accumFrom` doesn't begin accumulating state at all. Only when\n  someone starts observing the result of `accumFrom` is state accumulated.\n  This is very counter intuitive behavior.\n- Calling `accumFrom` starts accumulating state from when `accumFrom` is called.\n  This is pretty easy to understand. But it makes `accumFrom` impure as it\n  will not return the same behavior when called at different time.\n\nTo solve this problem Hareactive uses a solution invented by Atze van\nder Ploeg and presented in his paper \"Principled Practical FRP\". His\nbrilliant idea gives Hareactive the best of both worlds. Intuitive\nbehavior and purity.\n\nThe solution means that some functions return a value that, compared\nto what one might expect, is wrapped in an \"extra\" behavior. This\n\"behavior wrapping\" is applied to all functions that return a result\nthat depends on the past. The before mentioned `accumFrom`, for instance,\nreturns a value of type `Behavior\u003cBehavior\u003cA\u003e\u003e`.\n\nRemember that a behavior is a value that depends on time. It is a\nfunction from time. Therefore a behavior of a behavior is like a value\nthat depends on _two_ moments in time. This makes sense for `accumFrom`\nbecause the result of accumulating depends both on when we _start_\naccumulating and where we are now.\n\nTo get rid of the extra layer of nesting we often use `sample`. The\n`sample` function returns a `Now`-computation that asks for the\ncurrent value of a behavior. It has the type `(b: Behavior\u003cA\u003e) =\u003e Now\u003cA\u003e`. Using `sample` with `accumFrom` looks like this.\n\n```js\nconst count = sample(accumFrom((acc, inc) =\u003e acc + inc, 0, incrementStream));\n```\n\nHere `count` has type `Now\u003cBehavior\u003cA\u003e\u003e` and it represents a\n`Now`-computation that will start accumulating from the present\nmoment.\n\n## Flattening nested FRP values\n\nThe definition of higher-order FRP is that it allows for FRP primitives nested\ninside other FRP primitives. Combinations like streams of streams, behaviors of\nbehaviors, streams of futures, and any others are possible.\n\nThe benefit of higher-order FRP is increased expressiveness that makes it\npossibe to express many real-world scenarios with ease. One example would be an\napplication with a list of counters. Each counter has a value which can be\nrepresented as a `Behavior\u003cnumber\u003e`. A list of counters would then have the type\n`Array\u003cBehavior\u003cnumber\u003e\u003e`. If additionally the list itself can change (maybe new\ncounters can be added) then the type whould be\n`Behavior\u003cArray\u003cBehavior\u003cnumber\u003e\u003e`. This higher-order type nicely captures that\nwe have a _changing_ list of _changing_ numbers.\n\nThe downside of higher-order FRP is that sometimes dealing with these nested\ntypes can be tricky. Hareactive provides a number of functions to help with\nthis. The table below gives an overview.\n\n| Outer    | Inner    | Function                   |\n| -------- | -------- | -------------------------- |\n| Behavior | anything | `sample` (when inside Now) |\n| Behavior | Behavior | `flat`                     |\n| Behavior | Stream   | `shiftCurrent`             |\n| Stream   | Behavior | `switcher`, `selfie`       |\n| Stream   | Stream   | `shift`                    |\n| Stream   | Future   | n/a                        |\n| Future   | Behavior | `switchTo`                 |\n\n## Tutorial/cookbook\n\nThis cookbook will demonstrate how to use Hareactive. The examples\ngradually increase in complexity. Reading from the top serves as an\ntutorial about the library.\n\nPlease open an issue if anything is unclear from the explanations\ngiven.\n\n### General\n\n#### How do I apply a function to the value inside a behavior?\n\nYou can use the `map` method. For instance, if you have a behavior of\na number you can square the number as follows. `map` returns a new\nbehavior with all values of the original behavior passed through the function:\n\n```js\nbehaviorOfNumber.map((n) =\u003e n * n);\n```\n\n`map` is also available as a function instead of a method.\n\n```js\nmap((n) =\u003e n * n, behaviorOfNumber);\n```\n\n#### Can I also apply a function to the occurrences in a stream?\n\nYes. Streams also have a `map` method.\n\n```js\nstreamOfNumbers.map((n) =\u003e n * n);\n```\n\nThe `map` function also works with streams.\n\n```js\nmap((n) =\u003e n * n, streamOfNumbers);\n```\n\n#### If I have two streams how can I merge them into one with the occurrences from both?\n\nThis is done with the `combine` method or the `combine` function.\n\n```js\ncombine(firstStream, secondStream);\n```\n\nYou can similarly combine any number of streams:\n\n```js\ncombine(firstStream, secondStream, thirdStream, etcStream);\n```\n\n#### How do I combine two behaviors?\n\nBehaviors always have a current value. So to combine them you will\nhave to specify how to turn the two values from the two behaviors into\na single value. You do that with the `lift` function.\n\nFor instance, if you have two behaviors of numbers you can combine\nthem by adding their values together.\n\n```js\nlift((n, m) =\u003e n + m, behaviorN, behaviorM);\n```\n\nYou can also combine in this fashion any number of behaviors,\nwhich has to match the number of the function arguments:\n\n```js\nlift((n, m, q) =\u003e (n + m) / q, behaviorN, behaviorM, behaviorQ);\n```\n\n#### How do I turn a stream into a behavior?\n\nYou probably want `stepperFrom`:\n\n```js\nconst b = stepperFrom(initial, stream);\n```\n\n### Creating behaviors and streams\n\n#### Can I create a stream from events on a DOM element?\n\nWe've though of that. Hareactive comes with a function for doing just\nthat:\n\n```js\nstreamFromEvent(domElement, \"click\");\n```\n\n#### Can I turn an item in `localStorage` into a behavior?\n\nDefinitely. Yes. `fromFunction` takes an impure function and turns it\ninto a behavior whose value at any time is equal to what the impure\nfunction would return at that time:\n\n```js\nconst localStorageBehavior = fromFunction(() =\u003e localStorage.getItem(\"foobar\"));\n```\n\n### Debugging\n\n#### My program isn't working. Is there an easy way to check what is going on in my behaviors or streams?\n\nBoth streams and behaviors have a `log` method that logs to the\nconsole when something happens.\n\n```js\nmisbehavingStream.log();\n```\n\n## API\n\n### Future\n\n#### `Future.of\u003cA\u003e(a: A): Future\u003cA\u003e`\n\nConverts any value into a future that has \"always occurred\". Semantically `Future.of(a)` is equivalent to `(-Infinity, a)`.\n\n#### `fromPromise\u003cA\u003e(p: Promise\u003cA\u003e): Future\u003cA\u003e`\n\nConverts a promise to a future.\n\n#### `isFuture(f: any): f is Future\u003cany\u003e`\n\nReturns `true` if `f` is a future and `false` otherwise.\n\n#### `Future#listen\u003cA\u003e(o: Consumer\u003cA\u003e): void`\n\nAdds a consumer as listener to a future. If the future has already\noccurred the consumer is immediately pushed to.\n\n### Stream\n\n#### `empty: Stream\u003cany\u003e`\n\nEmpty stream.\n\n#### ~`Stream.of\u003cA\u003e(a: A): Stream\u003cA\u003e`~\n\nThis function does not exist. Use `empty` to create a dummy stream for testing purposes.\n\n#### `isStream(s: any): s is Stream\u003cany\u003e`\n\nReturns `true` if `s` is a stream and `false` otherwise.\n\n#### `apply\u003cA, B\u003e(behavior: Behavior\u003c(a: A) =\u003e B\u003e, stream: Stream\u003cA\u003e): Stream\u003cB\u003e`\n\nApplies a function-valued behavior to a stream. Whenever the stream\nhas an occurrence the value is passed through the current function of\nthe behavior.\n\n#### `filter\u003cA\u003e(predicate: (a: A) =\u003e boolean, s: Stream\u003cA\u003e): Stream\u003cA\u003e`\n\nReturns a stream with all the occurrences from `s` for which\n`predicate` returns `true`.\n\n```js\nconst stream = testStreamFromArray([1, 3, 2, 4, 1]);\nconst filtered = stream.filter((n) =\u003e n \u003e 2);\nfiltered.semantic(); //=\u003e [{ time: 1, value: 3 }, { time: 3, value: 4 }]\n```\n\n#### `split\u003cA\u003e(predicate: (a: A) =\u003e boolean, stream: Stream\u003cA\u003e): [Stream\u003cA\u003e, Stream\u003cA\u003e]`\n\nReturns a pair of streams. The first contains all occurrences from\n`stream` for which `predicate` returns `true` and the other the\noccurrences for which `predicate` returns `false`.\n\n```js\nconst whereTrue = stream.filter(predicate);\nconst whereFalse = stream.filter((v) =\u003e !predicate(v));\n// is equivalent to\nconst [whereTrue, whereFalse] = split(predicate, stream);\n```\n\n#### `filterApply\u003cA\u003e(predicate: Behavior\u003c(a: A) =\u003e boolean\u003e, stream: Stream\u003cA\u003e): Stream\u003cA\u003e`\n\nFilters a stream by applying the predicate-valued behavior to all\noccurrences.\n\n#### `keepWhen\u003cA\u003e(stream: Stream\u003cA\u003e, behavior: Behavior\u003cboolean\u003e): Stream\u003cA\u003e`\n\nWhenever `stream` has an occurrence the current value of `behavior` is\nconsidered. If it is `true` then the returned stream also has the\noccurrence—otherwise it doesn't. The behavior works as a filter that\ndecides whether or not values are let through.\n\n#### `scanFrom\u003cA, B\u003e(fn: (a: A, b: B) =\u003e B, startingValue: B, stream: Stream\u003cA\u003e): Behavior\u003cStream\u003cB\u003e\u003e`\n\nA stateful scan.\n\n#### `snapshot\u003cB\u003e(b: Behavior\u003cB\u003e, s: Stream\u003cany\u003e): Stream\u003cB\u003e`\n\nCreates a stream that occurs exactly when `s` occurs. Every time the stream `s`\nhas an occurrence the current value of `b` is sampled. The value in the\noccurrence is then replaced with the sampled value.\n\n```js\nconst stream = testStreamFromObject({\n  1: 0,\n  4: 0,\n  8: 0,\n  12: 0\n});\nconst shot = snapshot(time, stream);\nconst result = testStreamFromObject({\n  1: 1,\n  4: 4,\n  8: 8,\n  12: 12\n});\n// short == result\n```\n\n#### `snapshotWith\u003cA, B, C\u003e(f: (a: A, b: B) =\u003e C, b: Behavior\u003cB\u003e, s: Stream\u003cA\u003e): Stream\u003cC\u003e`\n\nReturns a stream that occurs whenever `s` occurs. At each occurrence\nthe value from `s` and the value from `b` is passed to `f` and the\nreturn value is the value of the returned streams occurrence.\n\n#### `shiftCurrent\u003cA\u003e(b: Behavior\u003cStream\u003cA\u003e\u003e): Stream\u003cA\u003e`\n\nTakes a stream valued behavior and returns a stream that emits values from the\ncurrent stream at the behavior. I.e. the returned stream always \"shifts\" to the\ncurrent stream at the behavior.\n\n#### `shift`\n\n```typescript\nfunction shift\u003cA\u003e(s: Stream\u003cStream\u003cA\u003e\u003e): Now\u003cStream\u003cA\u003e\u003e;\n```\n\nTakes a stream of a stream and returns a stream that emits from the last\nstream.\n\n#### `shiftFrom`\n\n```typescript\nfunction shiftFrom\u003cA\u003e(s: Stream\u003cStream\u003cA\u003e\u003e): Behavior\u003cStream\u003cA\u003e\u003e;\n```\n\nTakes a stream of a stream and returns a stream that emits from the last\nstream.\n\n#### changes\n\n```ts\nchanges\u003cA\u003e(b: Behavior\u003cA\u003e, comparator: (v: A, u: A) =\u003e boolean = (v, u) =\u003e v === u): Stream\u003cA\u003e;\n```\n\nTakes a behavior and returns a stream that has an occurrence whenever\nthe behaviors value changes.\n\nThe second argument is an optional comparator that will be used to determine\nequality between values of the behavior. It defaults to using `===`. This\ndefault is only intended to be used for JavaScript primitives like booleans,\nnumbers, strings, etc.\n\n#### `combine\u003cA, B\u003e(a: Stream\u003cA\u003e, b: Stream\u003cB\u003e): Stream\u003c(A|B)\u003e`\n\nCombines two streams into a single stream that contains the\noccurrences of both `a` and `b` sorted by the time of their\noccurrences. If two occurrences happens at the exactly same time then\nthe occurrence from `a` comes first.\n\n```js\nconst s1 = testStreamFromObject({ 0: \"#1\", 2: \"#3\" });\nconst s2 = testStreamFromObject({ 1: \"#2\", 2: \"#4\", 3: \"#5\" });\nconst combined = combine(s1, s2);\nassert.deepEqual(combined.semantic(), [\n  { time: 0, value: \"#1\" },\n  { time: 1, value: \"#2\" },\n  { time: 2, value: \"#3\" },\n  { time: 2, value: \"#4\" },\n  { time: 3, value: \"#5\" }\n]);\n```\n\n#### `isStream(obj: any): boolean`\n\nReturns `true` if `obj` is a stream and `false` otherwise.\n\n```js\nisStream(empty); //=\u003e true\nisStream(12); //=\u003e false\n```\n\n#### `delay\u003cA\u003e(ms: number, s: Stream\u003cA\u003e): Stream\u003cA\u003e`\n\nReturns a stream that occurs `ms` milliseconds after `s` occurs.\n\n#### `throttle\u003cA\u003e(ms: number, s: Stream\u003cA\u003e): Stream\u003cA\u003e`\n\nReturns a stream that after occurring, ignores the next occurrences in\n`ms` milliseconds.\n\n#### `stream.log(prefix?: string)`\n\nThe log method on streams logs the value of every occurrence using\n`console.log`. It is intended to be used for debugging streams during\ndevelopment.\n\nThe option `prefix` argument will be logged along with every value if specified.\n\n```\nmyStream.log(\"myStream:\");\n```\n\n### Behavior\n\n#### `Behavior.of\u003cA\u003e(a: A): Behavior\u003cA\u003e`\n\nConverts any value into a constant behavior.\n\n#### `fromFunction\u003cB\u003e(fn: () =\u003e B): Behavior\u003cB\u003e`\n\nThis takes an impure function that varies over time and returns a\npull-driven behavior. This is particularly useful if the function is\ncontionusly changing, like `Date.now`.\n\n#### `isBehavior(b: any): b is Behavior\u003cany\u003e`\n\nReturns `true` if `b` is a behavior and `false` otherwise.\n\n#### `whenFrom(b: Behavior\u003cboolean\u003e): Behavior\u003cFuture\u003c{}\u003e\u003e`\n\nTakes a boolean valued behavior an returns a behavior that at any\npoint in time contains a future that occurs in the next moment where\n`b` is `true`.\n\n#### `snapshot\u003cA\u003e(b: Behavior\u003cA\u003e, f: Future\u003cany\u003e): Behavior\u003cFuture\u003cA\u003e\u003e`\n\nCreates a future than on occurence samples the current value of the\nbehavior and occurs with that value. That is, the original value of\nthe future is overwritten with the behavior value at the time when the\nfuture occurs.\n\n#### `stepTo\u003cA\u003e(init: A, next: Future\u003cA\u003e): Behavior\u003cA\u003e`\n\nFrom an initial value and a future value, `stepTo` creates a new behavior\nthat has the initial value until `next` occurs, after which it has the value\nof the future.\n\n#### `switchTo\u003cA\u003e(init: Behavior\u003cA\u003e, next: Future\u003cBehavior\u003cA\u003e\u003e): Behavior\u003cA\u003e`\n\nCreates a new behavior that acts exactly like `initial` until `next`\noccurs after which it acts like the behavior it contains.\n\n#### `switcher\u003cA\u003e(init: Behavior\u003cA\u003e, s: Stream\u003cBehavior\u003cA\u003e\u003e): Now\u003cBehavior\u003cA\u003e\u003e`\n\nA behavior of a behavior that switches to the latest behavior from `s`.\n\n#### `switcherFrom\u003cA\u003e(init: Behavior\u003cA\u003e, s: Stream\u003cBehavior\u003cA\u003e\u003e): Behavior\u003cBehavior\u003cA\u003e\u003e`\n\nA behavior of a behavior that switches to the latest behavior from `s`.\n\n#### `stepperFrom\u003cB\u003e(initial: B, steps: Stream\u003cB\u003e): Behavior\u003cBehavior\u003cB\u003e\u003e`\n\nCreates a behavior whose value is the last occurrence in the stream.\n\n#### `scanFrom\u003cA, B\u003e(fn: (a: A, b: B) =\u003e B, init: B, source: Stream\u003cA\u003e): Behavior\u003cBehavior\u003cB\u003e\u003e`\n\nThe returned behavior initially has the initial value, on each\noccurrence in `source` the function is applied to the current value of\nthe behaviour and the value of the occurrence, the returned value\nbecomes the next value of the behavior.\n\n#### `moment\u003cA\u003e(f: (sample: \u003cB\u003e(b: Behavior\u003cB\u003e) =\u003e B) =\u003e A): Behavior\u003cA\u003e`\n\nConstructs a behavior based on a function. At any point in time the value of\nthe behavior is equal to the result of applying the function to a sampling\nfunction. The sampling function returns the current value of any behavior.\n\n`moment` is a powerful function that can do many things and sometimes it can do\nthem in a way that is a lot easier than other functions. A typical usage of\n`moment` has the following form.\n\n```js\nmoment((at) =\u003e {\n  ...\n})\n```\n\nAbove, the `at` function above can be applied to any behavior and it will\nreturn the current value of the behavior. The following example adds together\nthe values of three behaviors of numbers.\n\n```js\nconst sum = moment((at) =\u003e at(aBeh) + at(bBeh) + at(cBeh));\n```\n\nThe above could also be achieved with `lift`. However, `moment` can give better\nperformance when used with a function which dynamically switches which\nbehaviors it depends on. To understand this, consider the following contrived\nexample.\n\n```js\nconst lifted = lift((a, b, c, d) =\u003e (a \u0026\u0026 b ? c : d), aB, bB, cB, dB);\n```\n\nHere the resulting behavior will _always_ depend on both `aB`, `bB`, `cB`,\n`dB`. This means that if any of them changes then the value of `lifted` will be\nrecomputed. But, if for instance, `aB` is `false` then the function actually\nonly uses `aB` and there is no need to recompute `lifted` if any of the other\nbehaviors changes. However, `lift` can't know this since the function given to\nit is just a \"black box\".\n\nIf, on the other hand, we use `moment`:\n\n```js\nconst momented = moment((at) =\u003e (at(aB) \u0026\u0026 at(bB) ? at(cB) : at(dB)));\n```\n\nThen `moment` can simply check which behaviors are actually sampled inside the\nfunction passed to it, and it uses this information to figure out which\nbehaviors `momented` depends upon in any given time. This means that when `aB`\nis `false` the implementation can figure out that, currently, `momented` only\ndepends on `atB` and there is no need to recompute `momented` when any of the\nother behaviors changes.\n\n`moment` can also be very useful with behaviors nested inside behaviors. If\n`persons` is a behavior of an array of persons and is of the type `Behavior\u003c{ age: Behavior\u003cnumber\u003e, name: string }[]\u003e` then the following code creates a\nbehavior that at any time is equal to the name of the first person in the array\nwhose age is greater than 20.\n\n```js\nconst first = moment((at) =\u003e {\n  for (const person of at(persons)) {\n    if (at(person.age) \u003e 20) {\n      return person.name;\n    }\n  }\n});\n```\n\nAchieving something similar without `moment` would be quite tricky.\n\n#### `time: Behavior\u003cTime\u003e`\n\nA behavior whose value is the number of milliseconds elapsed since UNIX epoch.\nI.e. its current value is equal to the value got by calling `Date.now`.\n\n#### `measureTime: Now\u003cBehavior\u003cTime\u003e\u003e`\n\nThe now-computation results in a behavior that tracks the time passed since its\ncreation.\n\n#### `measureTimeFrom: Behavior\u003cBehavior\u003cTime\u003e\u003e`\n\nA behavior giving access to continuous time. When sampled the outer\nbehavior gives a behavior with values that contain the difference\nbetween the current sample time and the time at which the outer\nbehavior was sampled.\n\n#### `integrate(behavior: Behavior\u003cnumber\u003e): Behavior\u003cBehavior\u003cnumber\u003e\u003e`\n\nIntegrate behavior with respect to time.\n\nThe value of the behavior is treated as a rate of change per millisecond.\n\n#### `integrateFrom(behavior: Behavior\u003cnumber\u003e): Behavior\u003cBehavior\u003cnumber\u003e\u003e`\n\nIntegrate behavior with respect to time.\n\nThe value of the behavior is treated as a rate of change per millisecond.\n\n#### `behavior.log(prefix?: string, ms: number = 100)`\n\nThe log method on behaviors logs the value of the behavior whenever it changes\nusing `console.log`. It is intended to be used for debugging behaviors during\ndevelopment.\n\nIf the behavior is a pull behavior (i.e. it may change infinitely often) then\nchanges will only be logged every `ms` milliseconds.\n\nThe option `prefix` argument will be logged along with every value if specified.\n\n```\nmyBehavior.log(\"myBehavior:\");\ntime.map(t =\u003e t * t).log(\"Time squared is:\", 1000);\n```\n\n### Now\n\nThe Now monad represents a computation that takes place in a given\nmoment and where the moment will always be now when the computation is\nrun.\n\n#### `Now.of\u003cA\u003e(a: A): Now\u003cA\u003e`\n\nConverts any value into the Now monad.\n\n#### `async\u003cA\u003e(comp: IO\u003cA\u003e): Now\u003cFuture\u003cA\u003e\u003e`\n\nRun an asynchronous IO action and return a future in the Now monad\nthat resolves with the eventual result of the IO action once it\ncompletes. This function is what allows the Now monad to execute\nimperative actions in a way that is pure and integrated with FRP.\n\n#### `sample\u003cA\u003e(b: Behavior\u003cA\u003e): Now\u003cA\u003e`\n\nReturns the current value of a behavior in the Now monad. This is\npossible because computations in the Now monad have an associated\npoint in time.\n\n#### `performStream\u003cA\u003e(s: Stream\u003cIO\u003cA\u003e\u003e): Now\u003cStream\u003cA\u003e\u003e`\n\nTakes a stream of `IO` actions and return a stream in a now\ncomputation. When run the now computation executes each `IO` action\nand delivers their result into the created stream.\n\n#### `performStreamLatest\u003cA\u003e(s: Stream\u003cIO\u003cA\u003e\u003e): Now\u003cStream\u003cA\u003e\u003e`\n\nA variant of `performStream` where outdated `IO` results are ignored.\n\n#### `performStreamOrdered\u003cA\u003e(s: Stream\u003cIO\u003cA\u003e\u003e): Now\u003cStream\u003cA\u003e\u003e`\n\nA variant of `performStream` where `IO` results occur in the same order.\n\n#### `plan\u003cA\u003e(future: Future\u003cNow\u003cA\u003e\u003e): Now\u003cFuture\u003cA\u003e\u003e`\n\nConvert a future now computation into a now computation of a future.\nThis function is what allows a Now-computation to reach beyond the\ncurrent moment that it is running in.\n\n#### `runNow\u003cA\u003e(now: Now\u003cFuture\u003cA\u003e\u003e): Promise\u003cA\u003e`\n\nRun the given Now-computation. The returned promise resolves once the\nfuture that is the result of running the now computation occurs. This\nis an impure function and should not be used in normal application\ncode.\n\n## Contributing\n\nContributions are very welcome. Development happens as follows:\n\nInstall dependencies.\n\n```\nnpm install\n```\n\nRun tests.\n\n```\nnpm test\n```\n\nRunning the tests will generate an HTML coverage report in `./coverage/`.\n\nContinuously run the tests with\n\n```\nnpm run test-watch\n```\n\nWe also use `tslint` for ensuring a coherent code-style.\n\n## Benchmark\n\nGet set up to running the benchmarks:\n\n```\nnpm run build\n./benchmark/prepare-benchmarks.sh\n```\n\nRun all benchmarks with:\n\n```\nnpm run bench\n```\n\nRun a single benchmark with:\n\n```\nnode benchmark/\u003cname-of-benchmark\u003e\n```\n\nFor example\n\n```\nnode benchmark/scan.suite\n```\n","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffunkia%2Fhareactive","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffunkia%2Fhareactive","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffunkia%2Fhareactive/lists"}