Skip to content

Instantly share code, notes, and snippets.

@zerobias
Last active September 12, 2018 04:20
Show Gist options
  • Save zerobias/84925f30334eee0d419302d30d60bbd7 to your computer and use it in GitHub Desktop.
Save zerobias/84925f30334eee0d419302d30d60bbd7 to your computer and use it in GitHub Desktop.
Transmutation with effector (aka histomorphism)
//@flow
import {createStore, type Store} from 'effector'
const capacity: '@@capacity' = (Symbol('buffer capacity'): any)
declare export function readCapacity<T>(store: Store<[T, T, T, T, T, T, T]>): 7
declare export function readCapacity<T>(store: Store<[T, T, T, T, T, T]>): 6
declare export function readCapacity<T>(store: Store<[T, T, T, T, T]>): 5
declare export function readCapacity<T>(store: Store<[T, T, T, T]>): 4
declare export function readCapacity<T>(store: Store<[T, T, T]>): 3
declare export function readCapacity<T>(store: Store<[T, T]>): 2
declare export function readCapacity<T>(store: Store<[T]>): 1
declare export function readCapacity<T>(store: Store<Array<T>>): number
declare export function readCapacity<T>(store: Store<T>): 0
export function readCapacity(store: mixed): number {
return typeof store === 'object' &&
store !== null &&
typeof store[capacity] === 'number'
? store[capacity]
: 0
}
declare export function createBuffer<T>(n: 1, store: Store<T>): Store<[T]>
declare export function createBuffer<T>(n: 2, store: Store<T>): Store<[T, T]>
declare export function createBuffer<T>(n: 3, store: Store<T>): Store<[T, T, T]>
declare export function createBuffer<T>(
n: 4,
store: Store<T>,
): Store<[T, T, T, T]>
declare export function createBuffer<T>(
n: 5,
store: Store<T>,
): Store<[T, T, T, T, T]>
declare export function createBuffer<T>(
n: 6,
store: Store<T>,
): Store<[T, T, T, T, T, T]>
declare export function createBuffer<T>(
n: 7,
store: Store<T>,
): Store<[T, T, T, T, T, T, T]>
declare export function createBuffer<T>(
n: number,
store: Store<T>,
): Store<$ReadOnlyArray<T>>
export function createBuffer<T>(n: number, store: Store<T>): Store<Array<T>> {
const buffered = store.map((data, state: Array<T>) => {
if (state.length < n - 1) return [data, ...state]
return [data, ...state.slice(0, -1)]
}, [])
//$off
buffered[capacity] = n
return buffered
}
declare export function createTransit<T>(
opts: $ReadOnly<{
store: Store<[T]>,
pred: (a: T) => boolean,
map: (a: T) => T,
}>,
): Store<[T]>
declare export function createTransit<T>(
opts: $ReadOnly<{
store: Store<[T, T]>,
pred: (a: T, b: T) => boolean,
map: (a: T, b: T) => T,
}>,
): Store<[T, T]>
declare export function createTransit<T>(
opts: $ReadOnly<{
store: Store<[T, T, T]>,
pred: (a: T, b: T, c: T) => boolean,
map: (a: T, b: T, c: T) => T,
}>,
): Store<[T, T, T]>
declare export function createTransit<T>(
opts: $ReadOnly<{
store: Store<[T, T, T, T]>,
pred: (a: T, b: T, c: T, d: T) => boolean,
map: (a: T, b: T, c: T, d: T) => T,
}>,
): Store<[T, T, T, T]>
declare export function createTransit<T>(
opts: $ReadOnly<{
store: Store<[T, T, T, T, T]>,
pred: (a: T, b: T, c: T, d: T, e: T) => boolean,
map: (a: T, b: T, c: T, d: T, e: T) => T,
}>,
): Store<[T, T, T, T, T]>
declare export function createTransit<T>(
opts: $ReadOnly<{
store: Store<[T, T, T, T, T, T]>,
pred: (a: T, b: T, c: T, d: T, e: T, f: T) => boolean,
map: (a: T, b: T, c: T, d: T, e: T, f: T) => T,
}>,
): Store<[T, T, T, T, T, T]>
declare export function createTransit<T>(
opts: $ReadOnly<{
store: Store<[T, T, T, T, T, T, T]>,
pred: (a: T, b: T, c: T, d: T, e: T, f: T, _: T) => boolean,
map: (a: T, b: T, c: T, d: T, e: T, f: T, _: T) => T,
}>,
): Store<[T, T, T, T, T, T, T]>
declare export function createTransit<T>(
opts: $ReadOnly<{
store: Store<$ReadOnlyArray<T>>,
pred: (...values: Array<T>) => boolean,
map: (...values: Array<T>) => T,
}>,
): Store<$ReadOnlyArray<T>>
export function createTransit<T>({
store,
pred,
map,
}: {
store: Store<Array<T>>,
pred: (...values: Array<T>) => boolean,
map: (...values: Array<T>) => T,
}): Store<Array<T>> {
const size = readCapacity(store)
const result = store.map(list => {
if (list.length < size) return list
if (pred(...list)) return [map(...list), ...list.slice(1)]
return list
})
//$off
result[capacity] = size
return result
}
export function readHead<T>(store: Store<$ReadOnlyArray<T>>): Store<T> {
return store.map(([state]) => state)
}
declare export function transition<T>(opts: {
n: 7,
store: Store<T>,
pred: (a: T, b: T, c: T, d: T, e: T, f: T, _: T) => boolean,
map: (a: T, b: T, c: T, d: T, e: T, f: T, _: T) => T,
}): Store<T>
declare export function transition<T>(opts: {
n: 6,
store: Store<T>,
pred: (a: T, b: T, c: T, d: T, e: T, f: T) => boolean,
map: (a: T, b: T, c: T, d: T, e: T, f: T) => T,
}): Store<T>
declare export function transition<T>(opts: {
n: 5,
store: Store<T>,
pred: (a: T, b: T, c: T, d: T, e: T) => boolean,
map: (a: T, b: T, c: T, d: T, e: T) => T,
}): Store<T>
declare export function transition<T>(opts: {
n: 4,
store: Store<T>,
pred: (a: T, b: T, c: T, d: T) => boolean,
map: (a: T, b: T, c: T, d: T) => T,
}): Store<T>
declare export function transition<T>(opts: {
n: 3,
store: Store<T>,
pred: (a: T, b: T, c: T) => boolean,
map: (a: T, b: T, c: T) => T,
}): Store<T>
declare export function transition<T>(opts: {
n: 2,
store: Store<T>,
pred: (a: T, b: T) => boolean,
map: (a: T, b: T) => T,
}): Store<T>
declare export function transition<T>(opts: {
n: 1,
store: Store<T>,
pred: (a: T) => boolean,
map: (a: T) => T,
}): Store<T>
declare export function transition<T>(opts: {
n: 0,
store: Store<T>,
pred: () => boolean,
map: () => T,
}): Store<T>
declare export function transition<T>(opts: {
n: number,
store: Store<T>,
pred: (...args: Array<T>) => boolean,
map: (...args: Array<T>) => T,
}): Store<T>
export function transition<T>({
n,
store,
pred,
map,
}: {
n: number,
store: Store<T>,
pred: (...args: Array<T>) => boolean,
map: (...args: Array<T>) => T,
}): Store<T> {
const buffer: Store<$ReadOnlyArray<T>> = createBuffer(n, store)
return readHead(createTransit({store: buffer, pred, map}))
}
declare export function transmutation<T, M>(
opts: $ReadOnly<{
n: 7,
store: Store<M>,
of: (value: M) => T,
pred?: (a: T, b: T, c: T, d: T, e: T, f: T, _: T) => boolean,
map: (a: T, b: T, c: T, d: T, e: T, f: T, _: T) => T,
}>,
): Store<T>
declare export function transmutation<T, M>(
opts: $ReadOnly<{
n: 6,
store: Store<M>,
of: (value: M) => T,
pred?: (a: T, b: T, c: T, d: T, e: T, f: T) => boolean,
map: (a: T, b: T, c: T, d: T, e: T, f: T) => T,
}>,
): Store<T>
declare export function transmutation<T, M>(
opts: $ReadOnly<{
n: 5,
store: Store<M>,
of: (value: M) => T,
pred?: (a: T, b: T, c: T, d: T, e: T) => boolean,
map: (a: T, b: T, c: T, d: T, e: T) => T,
}>,
): Store<T>
declare export function transmutation<T, M>(
opts: $ReadOnly<{
n: 4,
store: Store<M>,
of: (value: M) => T,
pred?: (a: T, b: T, c: T, d: T) => boolean,
map: (a: T, b: T, c: T, d: T) => T,
}>,
): Store<T>
declare export function transmutation<T, M>(
opts: $ReadOnly<{
n: 3,
store: Store<M>,
of: (value: M) => T,
pred?: (a: T, b: T, c: T) => boolean,
map: (a: T, b: T, c: T) => T,
}>,
): Store<T>
declare export function transmutation<T, M>(
opts: $ReadOnly<{
n: 2,
store: Store<M>,
of: (value: M) => T,
pred?: (a: T, b: T) => boolean,
map: (a: T, b: T) => T,
}>,
): Store<T>
declare export function transmutation<T, M>(
opts: $ReadOnly<{
n: 1,
store: Store<M>,
of: (value: M) => T,
pred?: (a: T) => boolean,
map: (a: T) => T,
}>,
): Store<T>
declare export function transmutation<T, M>(
opts: $ReadOnly<{
n: number,
store: Store<M>,
of: (value: M) => T,
pred?: (...args: Array<T>) => boolean,
map: (...args: Array<T>) => T,
}>,
): Store<T>
export function transmutation<T, M>({
n,
store,
pred,
of,
map,
}: $ReadOnly<{
n: number,
store: Store<M>,
of: (value: M) => T,
pred?: (...args: Array<T>) => boolean,
map: (...args: Array<T>) => T,
}>): Store<T> {
return transition({
n: (n: typeof n),
store: store.map(of),
pred: pred || (() => true),
map,
})
}
export class Transmutator<T> {
mappers: Array<{
n: number,
pred(...args: Array<T>): boolean,
map(...args: Array<T>): T,
}>
constructor(
mappers: Array<{
n: number,
pred(...args: Array<T>): boolean,
map(...args: Array<T>): T,
}> = [],
) {
this.mappers = mappers
}
variant(
map: (a: T) => T = a => a,
pred: (a: T) => boolean = a => true,
): Transmutator<T> {
return new Transmutator([...this.mappers, {n: 1, pred, map}])
}
variant2(
map: (a: T, b: T) => T = (a, b) => a,
pred: (a: T, b: T) => boolean = (a, b) => true,
): Transmutator<T> {
return new Transmutator([...this.mappers, {n: 2, pred, map}])
}
variant3(
map: (a: T, b: T, c: T) => T = (a, b, c) => a,
pred: (a: T, b: T, c: T) => boolean = (a, b, c) => true,
): Transmutator<T> {
return new Transmutator([...this.mappers, {n: 3, pred, map}])
}
variant4(
map: (a: T, b: T, c: T, d: T) => T = (a, b, c, d) => a,
pred: (a: T, b: T, c: T, d: T) => boolean = (a, b, c, d) => true,
): Transmutator<T> {
return new Transmutator([...this.mappers, {n: 4, pred, map}])
}
predVariant(pred: (a: T) => boolean = a => true): Transmutator<T> {
return this.variant(a => a, pred)
}
predVariant2(
pred: (a: T, b: T) => boolean = (a, b) => true,
): Transmutator<T> {
return this.variant2((a, b) => a, pred)
}
predVariant3(
pred: (a: T, b: T, c: T) => boolean = (a, b, c) => true,
): Transmutator<T> {
return this.variant3((a, b, c) => a, pred)
}
predVariant4(
pred: (a: T, b: T, c: T, d: T) => boolean = (a, b, c, d) => true,
): Transmutator<T> {
return this.variant4((a, b, c, d) => a, pred)
}
of<M>(store: Store<M>, of: (_: M) => T): Store<T> {
const first: Store<T> = store.map(of)
let next: Store<T> = first
for (const {n, pred, map} of this.mappers) {
next = transition({n: (n: typeof n), store: next, map, pred})
}
return next
}
}
const foo: Store<number> = createStore(0)
const fooTransit = transmutation({
n: (3: 3),
store: foo,
of: (n: number): [number, 'asc' | 'dec' | 'unknown'] => [n, 'unknown'],
map([an], [bn, bt], [cn, ct]): [number, 'asc' | 'dec' | 'unknown'] {
if (an > bn && bn > cn) return [an, 'asc']
if (an < bn && bn < cn) return [an, 'dec']
return [an, 'unknown']
},
})
const mut: Transmutator<
[number, 'asc' | 'dec' | 'unknown'],
> = new Transmutator()
const mutResult = mut
.variant3(
([an]) => [an, 'asc'],
([an], [bn, bt], [cn, ct]) => an > bn && bn > cn,
)
.variant3(
([an]) => [an, 'dec'],
([an], [bn, bt], [cn, ct]) => an < bn && bn < cn,
)
.of(foo, n => [n, 'unknown'])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment