Skip to content

Commit

Permalink
cleanup and adds join/2
Browse files Browse the repository at this point in the history
  • Loading branch information
bwireman committed Mar 16, 2024
1 parent 4f787eb commit c37f452
Show file tree
Hide file tree
Showing 7 changed files with 323 additions and 186 deletions.
32 changes: 25 additions & 7 deletions dist/delay.d.mts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
/**
* Type representing a delayed effect to be lazily evaluated
*/
export type Delay$<FXE, FXD> = Continue<FXE, FXD> | Stop<FXE>
export type Delay$<FXE, FXD> = Continue<FXD, FXE> | Stop<FXE>


/**
Expand Down Expand Up @@ -37,21 +37,30 @@ export function flat_map<FYL, FYM, FYP>(
* Run a delayed effect and get the result
* short-circuiting if any in delay in the chain returns an Error
*/
export function run<FZO, FZP>(delayed: Delay$<FZO, FZP>): Result<FZO, FZP>
export function run<GAA, GAB>(delayed: Delay$<GAA, GAB>): Result<GAA, GAB>


/**
* returns a delay, that joins two delays. If `left` fails right will not be run, if either fails the result will be an Error
*/
export function join<FYW, FYX, FZA, FZB>(
left: Delay$<FYW, FYX>,
right: Delay$<FZA, FZB>
): Delay$<[FYW, FZA], [Option$<FYX>, Option$<FZB>]>


/**
* Returns a new Delay that will be re-attempted `retries` times with `delay` ms in-between
* NOTE: `delay` is ignored in JS
*/
export function retry<FYW, FYX>(delayed: Delay$<FYW, FYX>, retries: number, delay: number): Delay$<FYW, FYX>
export function retry<FZI, FZJ>(delayed: Delay$<FZI, FZJ>, retries: number, delay: number): Delay$<FZI, FZJ>


/**
* Returns a new Delay that will be re-attempted `retries` times with `delay` ms in-between
* NOTE: `delay` is ignored in JS
*/
export function retry_with_backoff<FZC, FZD>(delayed: Delay$<FZC, FZD>, retries: number): Delay$<FZC, FZD>
export function retry_with_backoff<FZO, FZP>(delayed: Delay$<FZO, FZP>, retries: number): Delay$<FZO, FZP>


/**
Expand All @@ -64,13 +73,13 @@ export function drain(delayed: Delay$<any, any>): null
/**
* Run every effect in sequence and get their results
*/
export function every<GAF, GAG>(effects: List<Delay$<GAF, GAG>>): List<Result<GAF, GAG>>
export function every<GAR, GAS>(effects: List<Delay$<GAR, GAS>>): List<Result<GAR, GAS>>


/**
* Repeat a Delay and return the results in a list
*/
export function repeat<FZY, FZZ>(delayed: Delay$<FZY, FZZ>, repetition: number): List<Result<FZY, FZZ>>
export function repeat<GAK, GAL>(delayed: Delay$<GAK, GAL>, repetition: number): List<Result<GAK, GAL>>


/**
Expand All @@ -91,7 +100,7 @@ export function any(effects: List<Delay$<any, any>>): boolean
* Attempt multiple Delays until one returns an Ok
* unlike `any/1` this will short circuit on the first Ok
*/
export function fallthrough<GBI, GBJ>(effects: List<Delay$<GBI, GBJ>>): Result<GBI, GBJ>
export function fallthrough<GBU, GBV>(effects: List<Delay$<GBU, GBV>>): Result<GBU, GBV>

export class Continue<FXD, FXE> extends CustomType {
constructor(effect: () => Result<any, any>)
Expand All @@ -108,6 +117,8 @@ export class Result<T, E> extends CustomType {
isOk(): boolean
}

export type Option$<GC> = Some<GC> | None

export class List<T> implements any {
head: T
tail: List<T>
Expand All @@ -124,3 +135,10 @@ export class CustomType {
[P in K]: this[P]
}): this
}

export class Some<GC> extends CustomType {
constructor(argument$0: GC)
0: GC
}

export class None extends CustomType {}
72 changes: 60 additions & 12 deletions dist/delay.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,22 @@ var __name = (target, value) => __defProp(target, "name", { value, configurable:

import { Ok as Ok7, Error as Error9, toList as toList7 } from "./extras/prelude.mjs"

import { CustomType as $CustomType } from "./extras/prelude.mjs"
var Some = class extends $CustomType {
static {
__name(this, "Some")
}
constructor(x0) {
super()
this[0] = x0
}
}
var None = class extends $CustomType {
static {
__name(this, "None")
}
}

import { Error as Error5 } from "./extras/prelude.mjs"
function is_ok(result) {
if (!result.isOk()) {
Expand Down Expand Up @@ -164,7 +180,13 @@ function repeat(a, times) {
__name(repeat, "repeat")

// build/dev/javascript/delay/delay.mjs
import { Error as Error10, toList as toList8, CustomType as $CustomType7, makeError } from "./extras/prelude.mjs"
import {
Ok as Ok8,
Error as Error10,
toList as toList8,
CustomType as $CustomType7,
makeError
} from "./extras/prelude.mjs"
var Continue = class extends $CustomType7 {
static {
__name(this, "Continue")
Expand Down Expand Up @@ -204,8 +226,8 @@ __name(chain, "chain")
*/
function map3(delayed, func) {
if (delayed instanceof Continue) {
let delayed_f = delayed.effect
let _pipe = chain(delayed_f, func)
let delayed_func = delayed.effect
let _pipe = chain(delayed_func, func)
return delay_effect(_pipe)
} else {
let err = delayed.err
Expand All @@ -220,10 +242,10 @@ __name(map3, "map")
function flatten(delayed) {
let _pipe = (() => {
if (delayed instanceof Continue) {
let delayed_f = delayed.effect
let delayed_func = delayed.effect
return () => {
let inner = (() => {
let $ = delayed_f()
let $ = delayed_func()
if ($.isOk()) {
let inner_delay = $[0]
return inner_delay
Expand All @@ -233,8 +255,8 @@ function flatten(delayed) {
}
})()
if (inner instanceof Continue) {
let inner_f = inner.effect
return inner_f()
let inner_func = inner.effect
return inner_func()
} else {
let err = inner.err
return new Error10(err)
Expand Down Expand Up @@ -271,14 +293,39 @@ __name(sleep, "sleep")
*/
function run(delayed) {
if (delayed instanceof Continue) {
let f = delayed.effect
return f()
let func = delayed.effect
return func()
} else {
let err = delayed.err
return new Error10(err)
}
}
__name(run, "run")

/**
* returns a delay, that joins two delays. If `left` fails right will not be run, if either fails the result will be an Error
*/
function join(left, right) {
let _pipe = /* @__PURE__ */ __name(() => {
let $ = run(left)
if (!$.isOk()) {
let err = $[0]
return new Error10([new Some(err), new None()])
} else {
let left_val = $[0]
let $1 = run(right)
if ($1.isOk()) {
let right_val = $1[0]
return new Ok8([left_val, right_val])
} else {
let err = $1[0]
return new Error10([new None(), new Some(err)])
}
}
}, "_pipe")
return delay_effect(_pipe)
}
__name(join, "join")
function do_retry(delayed, retries, delay, backoff) {
let delay$1 = (() => {
if (backoff) {
Expand Down Expand Up @@ -325,7 +372,7 @@ __name(retry_with_backoff, "retry_with_backoff")
* short-circuiting if any in the chain returns an Error
*/
function drain(delayed) {
run(delayed)
let $ = run(delayed)
return void 0
}
__name(drain, "drain")
Expand All @@ -342,7 +389,7 @@ function do_every(loop$effects, loop$results) {
loop$effects = rest
loop$results = toList8([run(head)], results)
} else {

Check warning on line 391 in dist/delay.mjs

View workflow job for this annotation

GitHub Actions / test

'$' is assigned a value but never used. Allowed unused vars must match /^_/u
throw makeError("todo", "delay", 176, "do_every", "Empty list", {})
throw makeError("todo", "delay", 198, "do_every", "Empty list", {})
}
}
}
Expand Down Expand Up @@ -404,7 +451,7 @@ function do_fallthrough(effects) {
return fallthrough(rest)
})
} else {
throw makeError("todo", "delay", 191, "do_fallthrough", "Empty list", {})
throw makeError("todo", "delay", 213, "do_fallthrough", "Empty list", {})
}
}
__name(do_fallthrough, "do_fallthrough")
Expand All @@ -426,6 +473,7 @@ export {
fallthrough,
flat_map,
flatten,
join,
map3 as map,
repeat2 as repeat,
retry,
Expand Down
3 changes: 2 additions & 1 deletion scripts/build_js.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ set -e

cd "$(dirname $0)/.."

./scripts/update.sh

gleam clean
rm -rf dist/delay.mjs
rm -rf dist/delay.d.js
Expand Down Expand Up @@ -34,7 +36,6 @@ cat dist/delay.mjs.tmp |
sed 's/var MIN_ARRAY_NODE.*//g' |
grep -v "gleam/.*mjs" |
grep -v "gleam_stdlib/.*mjs" |
sed 's/let $ = run/run/g' |
sed 's/\.\.\/gleam.mjs/.\/extras\/prelude.mjs/g' |
sed 's/\.\/gleam.mjs/.\/extras\/prelude.mjs/g' >dist/delay.mjs

Expand Down
9 changes: 8 additions & 1 deletion specs/test_dist.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// smoke tests to establish that the NPM code can be used
// & works as expected
import { delay_effect, map, run, repeat, fallthrough, every, any, all } from "../dist/delay.mjs"
import { delay_effect, map, join, run, repeat, fallthrough, every, any, all } from "../dist/delay.mjs"
import { get, ok, error, isOk, toList } from "../dist/extras/extras.mjs"
import { expect, test } from 'vitest'

Expand Down Expand Up @@ -43,6 +43,13 @@ test("map", () => {
expect(res2).toBe("shit!")
})

test("join", () => {
let d1 = delay_effect(() => ok(1))
let d2 = delay_effect(() => ok(2))

expect(get(run(join(d1, d2)))).toStrictEqual([1, 2])
})

test("repeat", () => {
let fin = 0
const d = delay_effect(() => {
Expand Down
36 changes: 29 additions & 7 deletions src/delay.gleam
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import gleam/list
import gleam/result
import gleam/option

/// Type representing a delayed effect to be lazily evaluated
pub opaque type Delay(val, error) {
Expand All @@ -9,7 +10,7 @@ pub opaque type Delay(val, error) {

/// Stores an effect to be run later, short circuiting on errors
pub fn delay_effect(func: fn() -> Result(val, error)) -> Delay(val, error) {
Continue(func)
Continue(effect: func)
}

/// Chains an operation onto an existing delay. The result of the current delay will be lazily passed to `func`
Expand All @@ -19,8 +20,8 @@ pub fn map(
func: fn(val) -> Result(f_res, error),
) -> Delay(f_res, error) {
case delayed {
Continue(delayed_f) ->
chain(delayed_f, func)
Continue(effect: delayed_func) ->
chain(delayed_func, func)
|> delay_effect

Stop(err) -> Stop(err)
Expand All @@ -41,15 +42,15 @@ pub fn flatten(
case delayed {
// depending on the state of delayed we either need a fn that returns the stop error
// or a function that returns inner_res
Continue(delayed_f) -> fn() {
Continue(effect: delayed_func) -> fn() {
// run delayed_f and get or build a delay
let inner = case delayed_f() {
let inner = case delayed_func() {
Ok(inner_delay) -> inner_delay
Error(err) -> Stop(err)
}
// get the inner fn's resullt
case inner {
Continue(inner_f) -> inner_f()
Continue(effect: inner_func) -> inner_func()
Stop(err) -> Error(err)
}
}
Expand All @@ -70,6 +71,27 @@ pub fn flat_map(
|> flatten
}

/// returns a delay, that joins two delays. If `left` fails right will not be run, if either fails the result will be an Error
pub fn join(
left: Delay(left_val, left_error),
right: Delay(right_val, right_error),
) -> Delay(
#(left_val, right_val),
#(option.Option(left_error), option.Option(right_error)),
) {
fn() {
case run(left) {
Error(err) -> Error(#(option.Some(err), option.None))
Ok(left_val) ->
case run(right) {
Ok(right_val) -> Ok(#(left_val, right_val))
Error(err) -> Error(#(option.None, option.Some(err)))
}
}
}
|> delay_effect
}

/// Returns a new Delay that will be re-attempted `retries` times with `delay` ms in-between
/// NOTE: `delay` is ignored in JS
pub fn retry(
Expand Down Expand Up @@ -120,7 +142,7 @@ fn do_retry(
/// short-circuiting if any in delay in the chain returns an Error
pub fn run(delayed: Delay(val, error)) -> Result(val, error) {
case delayed {
Continue(f) -> f()
Continue(effect: func) -> func()
Stop(err) -> Error(err)
}
}
Expand Down

0 comments on commit c37f452

Please sign in to comment.