rentgen

A ReasonML generator library, designed for Deno and Node

Usage no npm install needed!

<script type="module">
  import rentgen from 'https://cdn.skypack.dev/rentgen';
</script>

README

Rentgen

A ReasonML generator library

Goals

  1. Uses an open api, which allows for the usage of fully in-reason generators, as well as external ones.
  2. Handling of sync and async generators.
  3. Written fully in Reason.

Documentation

Most of the documentation, together with examples, can be found inline

Sync


type next('a)

Represents the next value yielded by a generator

type gen('a)

Represents the api of a generator

next : gen('a) => next('a)

Increments the generator given, and returns its next) value.

return : (gen('a), 'a) => next('a)

Forces the generator to return the 2nd argument and stop.

throw : (gen('a), Js.Exn.t) => next('a)

Throws the error in the generator and forces it to stop.

from : 'a => gen('b)

Creates a generator from an external source, which implements the javascript generator api.

range : (~to_: int, ~from=0 : int, ~step=1 : int) => gen(int)

Creates a generator returning numbers from the range <from; to_> separated by the distance of step. Creates an int range.

range(~to_=10)->foldl((+), 0)
// => 55

from_list : list('a) => gen('a)

Converts a list to a generator.

[1,2,3]->from_list->foldl((+), 0)
// => 6

inf : 'a => ('a => 'a) => gen('a)

Creates an infinite generator from an initial value and a successor function.

inf(0, a => a + 1) // => <0, 1, 2, 3, ...>

map : (gen('a), ('a => 'b)) => gen('b)

Transforms the values of a generator.

range(~to_=5, ()) -> map(a => a * 2)
// => <0, 2, 4, 6, 8, 10>

keep : (gen('a), ('a => bool)) => gen('a)

Returns only the values of the generator which match the function.

range(~to_=10, ()) -> keep(a => a mod 2 == 0)
// => <0, 2, 4, 6, 8, 10>

consume : (gen('a), 'a => 'b) => unit

Consumes a generator with a function.

// prints an infinite generator
inf(0, a => a + 1) -> consume(Js.Console.log)
// 0
// 1
// 2 ...
// => unit

foldl : (gen('a), (('b, 'a) => 'b), 'b) => 'b

Folds a generator into a single value.

[1,2,3]->from_list->foldl((+), 0)
// => 6

foldl1 : (gen('a), ('b, 'a) => 'b) => 'b

Folds a generator into a single value, taking the first value as the initial value.

range(~to_=3, ~from=1,())
->map(float_of_int)
->foldl1((a, b) => a /. b)
// => 1/6

take : (gen('a), int) => gen('a)

Takes n values of the generator or until it ends.

inf(0, a => a + 1) -> take(5)
// => <0, 1, 2, 3, 4>

take_while : (gen('a), ('a => bool)) => gen('a)

Takes the values of the generator as long as the function returns true.

inf(0, a => a*2 + 1)->take_while(a => a < 15)
// => <0, 1, 3, 7>

Async


type async('a) = Js.Promise.t('a)

type next_async('a) = async(next('a))

type gen_async('a)

next_async : gen_async('a) => next_async('a)

Returns the next value of an async generator

return_async : (gen_async('a), 'a) => next_async('a)

Returns the value given (as a promise), and forces the generator to stop

throw_async : (gen_async('a), Js.Exn.t) => next_async('a)

Throw the given error in the generator and forces it to stop

from_async : 'a => gen_async('b)

Creates a generator from an external source, which implements the async iterator api.

from_sync : gen('a) => gen_async('a)

Converts a sync generator into an async one.

inf(1, a => a + 1)
->from_sync
->take_async(100)
->consume_async(Js.Console.log)

map_async : (gen_async('a), ('a => 'b)) => gen_async('b)

Transforms an async generator using the function given.

puppy_stream
-> map_async(pet)
// => <async("doggo_1"), async("doggo_2"), ...>

foldl_async : (gen_async('a), (('b, 'a) => 'b), 'b) => async('b)

Folds an async generetor into a single promise

open_file("data/numbers.txt")
->map_async(Js.Float.fromString)
->foldl_async((+.), 0.)
// => async(21)

foldl1_async : (gen_async('a), (('b, 'a) => 'b)) => [async('b)]

Folds an async generator into a single promise, taking the first value as the initial value.

range(~to_=3, ~from=1, ())
->map(float_of_int)
->from_sync
->foldl1_async((a, b) => a /. b)
// => async(1/6)

consume_async : (gen_async('a), 'a => 'b) => async(unit)

Consumes an async stream, and returns an empty promise.

from_async(Deno.iter(file, ()))
->consume_async(Js.Console.log)
// (prints the file)
// => async(unit)

take_async : (gen_async('a), int) => gen_async('a)

Takes the first n elements from the async generator, and returns a new one of the length n.

infinite_puppies
->take_async(5)
// => async<"puppy1", "puppy2", ... , "puppy5">

take_while_async : (gen_async('a), ('a => bool)) => gen_async('a)

Takes elements of the generator as long as the condition given is met. Returns a new async generator.

keep_async : (gen_async('a), ('a => bool)) => gen_async('a)

Returns an async generator of the items which meet the condition given.

Examples

Fizz-buzz

open Sync;

let () = inf(0, a => a + 1)
->map(a =>
   if (a mod 15 == 0) {
     "fizzbuzz";
   } else if (a mod 3 == 0) {
     "fizz";
   } else if (a mod 5 == 0) {
     "buzz";
   } else {
     Js.Int.toString(a);
   }
 )
->consume(Js.Console.log);