diff options
| author | Joris | 2023-02-19 13:19:05 +0100 | 
|---|---|---|
| committer | Joris | 2023-02-19 13:25:52 +0100 | 
| commit | 0267049f29374f0114bef23a5982c930c4d2bedb (patch) | |
| tree | 157cc1315e36723a2c7ef0f949e2136732d7e6bf /src | |
| parent | 8b84a732436fc6c84ce4b912b548648eb91c9312 (diff) | |
Add pure and sequence
Diffstat (limited to 'src')
| -rw-r--r-- | src/example.ts | 24 | ||||
| -rw-r--r-- | src/rx.ts | 84 | 
2 files changed, 103 insertions, 5 deletions
| diff --git a/src/example.ts b/src/example.ts index 5ff3fba..229d3a0 100644 --- a/src/example.ts +++ b/src/example.ts @@ -161,6 +161,30 @@ const doubleMapChild =      })    ) +const seq = +  withState(0, a => +    withState(0, b => +      withState(0, c => [ +        counterComponent({ +          value: a, +          onSub: () => a.update(n => n - 1), +          onAdd: () => a.update(n => n + 1) +        }), +        counterComponent({ +          value: b, +          onSub: () => b.update(n => n - 1), +          onAdd: () => b.update(n => n + 1) +        }), +        counterComponent({ +          value: c, +          onSub: () => c.update(n => n - 1), +          onAdd: () => c.update(n => n + 1) +        }), +        sequence2([a, b, c]).map(xs => xs.reduce((a, b) => a + b, 0)) +      ]) +    ) +  ) +  const view = h('main',    h('h1', 'Rx'),    chrono @@ -112,6 +112,21 @@ export class Rx<A> {    }  } +class Pure<A> extends Rx<A> { +  readonly type: 'Pure' +  readonly value: A + +  constructor(value: A) { +    super() +    this.type = 'Pure' +    this.value = value +  } +} + +export function pure<A>(value: A): Rx<A> { +  return new Pure(value) +} +  class Var<A> extends Rx<A> {    readonly type: 'Var'    readonly id: string @@ -151,6 +166,28 @@ class FlatMap<A, B> extends Rx<B> {    }  } +export function sequence<A>(xs: Array<Rx<A>>): Sequence<A> { +  return new Sequence<A>(xs) +} + +export function sequence2<A>(xs: Array<Rx<A>>): Rx<Array<A>> { +  return xs.reduce( +    (acc: Rx<Array<A>>, x: Rx<A>) => acc.flatMap(ys => x.map(y => [y, ...ys])), +    new Pure([]) +  ) +} + +class Sequence<A> extends Rx<Array<A>> { +  readonly type: 'Sequence' +  readonly xs: Array<Rx<A>> + +  constructor(xs: Array<Rx<A>>) { +    super() +    this.type = 'Sequence' +    this.xs = xs +  } +} +  // Mount  export function mount(html: Html): Cancelable { @@ -222,8 +259,15 @@ const voidRemove = () => {}  // Rx run -function rxRun<A>(state: State, rx: Rx<A>, effect: (value: A) => void): Cancelable { -  if (isVar(rx)) { +function rxRun<A>( +  state: State, +  rx: Rx<A>, +  effect: (value: A) => void +): Cancelable { +  if (isPure<A>(rx)) { +    effect(rx.value) +    return voidCancel +  } else if (isVar(rx)) {      const cancel = state.subscribe(rx, effect)      effect(state.get(rx))      return cancel @@ -239,13 +283,39 @@ function rxRun<A>(state: State, rx: Rx<A>, effect: (value: A) => void): Cancelab        cancel2()        cancel1()      } +  } else if (isSequence(rx)) { +    const cancels = Array(rx.xs.length).fill(voidCancel) +    const xs = Array(rx.xs.length).fill(undefined) +    let initEnded = false + +    rx.xs.forEach((rxChild, i) => { +      cancels[i] = rxRun( +        state, +        rxChild, +        (value: A) => { +          xs[i] = value +          if (initEnded) { +            // @ts-ignore +            effect(xs) +          } +        } +      ) +    }) +    // @ts-ignore +    effect(xs) +    initEnded = true +    return () => cancels.forEach(cancel => cancel())    } else {      throw new Error(`Unrecognized rx: ${rx}`)    }  }  function isRx<A>(x: any): x is Rx<A> { -  return x !== undefined && x.type !== undefined && (x.type === "Var" || x.type === "Map" || x.type === "FlatMap") +  return x !== undefined && x.type !== undefined && (x.type === "Var" || x.type === "Map" || x.type === "FlatMap" || x.type === 'Sequence' || x.type === 'Pure') +} + +function isPure<A>(x: any): x is Pure<A> { +  return x.type === 'Pure'  }  function isVar<A>(x: any): x is Var<A> { @@ -253,11 +323,15 @@ function isVar<A>(x: any): x is Var<A> {  }  function isMap<A, B>(x: any): x is Map<A, B> { -    return x.type === "Map" +  return x.type === "Map"  }  function isFlatMap<A, B>(x: any): x is FlatMap<A, B> { -    return x.type === "FlatMap" +  return x.type === "FlatMap" +} + +function isSequence<A>(x: any): x is Sequence<A> { +  return x.type === "Sequence"  }  // Append | 
