GHvW / lazer

:stars:Making iterables lazy, one generator at a time

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Lazer

The goal of lazer is to enable lazy evaluation for iterables.

Lazer aims to achieve its goal with three guiding principles

  1. Minimal TypeScript sugar - code should be easily translatable to regular ES6 JavaScript. Ideally, simply erasing type annotations would be the ES6 you would have written without TypeScript.
  2. No prototype extension - to avoid conflicts or changes to JavaScript in the future, no adding methods to Array.prototype, Map.prototype, or any other native JavaScript data structures.
  3. Minimal to no data structure lock-in - many JavaScript libraries that provide extensions for native types force you to use a special syntax or data structure to enable the extensions. While there is absolutely nothing wrong with that (and is often preferred), it locks you into that library's style. Once you're locked in, it can be hard to migrate to future enhancements to core JavaScript.

Lazer uses generators on stand-alone functions to enable this functionality.

Traditional Array.prototype methods like map, filter, reduce, etc. are provided as stand-alone functions instead of methods on a stream or sequence data structure. If a function takes multiple arguments, it is explicitely curried to provide maximum flexibility.

Examples

A traditional JavaScript Array method chain might look like this:

const arr =
    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
        .filter(n => n % 2 === 0)
        .map(n => n * 10); // [20, 40, 60, 80, 100]

To create the same ending final Array with lazer, you would write:

const arr = collect(toArray)(map(n => n * 10)(filter(n => n % 2 === 0)([1, 2, 3, 4, 5, 6, 7, 8, 9, 10].values())));

Gross, I know. If you're eyes are bleeding after looking at the exapmle, lazer provides a small Sequence class and Seq static class to facilitate a more fluent interface. Using Seq and Sequence, the lazer example can be written like this:

const arr =
    Seq.of(1, 2, 3, 4, 5, 6, 8, 9, 10) // could also be written `Seq.from([1, 2, 3, 4, 5, 6, 7, 8, 9, 10].values())
        .andThen(filter(n => n % 2 === 0))
        .andThen(map(n => n * 10))
        .collect(); // [20, 40, 60, 80, 100]

Use andThen to chain sequences together followed by a collect method to process the sequence. collect defaults to using the toArray function to transfrom the sequence into an array, but collect has the option to take a collector function to obtain different result types.

For exmaple, a sum function could be passed to collect to return the sum of all numbers in the sequence instead of an array:

const res =
    Seq.of(1, 2, 3, 4, 5, 6, 8, 9, 10) // could also be written `Seq.from([1, 2, 3, 4, 5, 6, 7, 8, 9, 10].values())
        .andThen(filter(n => n % 2 === 0))
        .andThen(map(n => n * 10))
        .collect(sum); // 300

Lazer's explicitely curried functions make it so that if a pipe operator makes it into JavaScript, the same sequence could be written something like this (depending on which pipe operator makes it into the spec):

    const arr =
        [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
        |> filter(n => n % 2 === 0)
        |> map(n => n * 10)
        |> collect(toArray)

Lazer is not going to be the right approach for everyone, and might not seem very Typescript-y or even JavaScript-y.

If you want a different library with similar aims, try out Sequency or Streamjs. Immutable js, Lodash, and RxJS may satisfy your needs as well.

As an alternative, if you don't want to deal with finding suite of JavaScript packages but still want a fully featured solution to many JavaScript pain points, try ClojureScript

About

:stars:Making iterables lazy, one generator at a time

License:MIT License


Languages

Language:TypeScript 100.0%