Compare commits

..

No commits in common. "e9216cc3e48b47f53ad7e95be0f95b35496757d5" and "e83fcd0b4de739380dfadd58b26c815a24038add" have entirely different histories.

View File

@ -1,29 +1,36 @@
import { type CursorPos } from 'node:readline' import { type CursorPos } from 'node:readline'
import type { Either } from '../util/basic/either' import type { Either } from '../util/basic/either'
import { none, type Option, some } from '../util/basic/option' import {
import { type Tag } from '../util/basic/utility' DoOption,
import { type CanvasEnd, type CanvasOrigin, end, origin } from './canvas' getOrElse,
none,
type Option,
some,
} from '../util/basic/option'
import { hasTag, pipe, type Tag } from '../util/basic/utility'
import {
type CanvasEnd,
type CanvasOrigin,
cursorPos,
end,
origin,
} from './canvas'
interface PainterExit<E> extends Tag<'PainterExit'> { interface PainterExit extends Tag<'PainterExit'> {}
value: Either<E, Error>
}
interface PainterTask<E, T extends object = {}> extends Tag<'PainterTask'> { interface PainterTask<T extends object = {}> extends Tag<'PainterTask'> {
task: { task: {
origin: CanvasOrigin, origin: CanvasOrigin,
end: CanvasEnd, end: CanvasEnd,
effect: PainterEffect<E, T>, effect: PainterEffect<T & Tag<'PainterState'>>,
state: Option<T & Tag<'PainterState'>>, state: Option<T & Tag<'PainterState'>>,
} }
} }
type TaskConstructor = ( type TaskConstructor<T extends object = {}> = (
x: CursorPos, x: CursorPos,
y: CursorPos, y: CursorPos,
) => <E = number, T extends object = {}>( ) => (f: PainterEffect, state?: T & Tag<'PainterState'>) => PainterTask<T>
f: PainterEffect<E, T>,
state?: T & Tag<'PainterState'>,
) => PainterTask<E, T>
const task: TaskConstructor = (x, y) => (f, state?) => { const task: TaskConstructor = (x, y) => (f, state?) => {
return { return {
_tag: 'PainterTask', _tag: 'PainterTask',
@ -36,22 +43,59 @@ const task: TaskConstructor = (x, y) => (f, state?) => {
} }
} }
type ExitConstructor = <T>(x: Either<T, Error>) => PainterExit<T>
const exit: ExitConstructor = x => ({_tag: 'PainterExit', value: x})
type PainterEffect< type PainterEffect<
E,
T extends object = {}, T extends object = {},
> = (task: PainterTask<T>) => Either<PainterTask<T>, PainterExit<E>> > = (task: PainterTask<T>) => Either<PainterTask<T>, PainterExit>
type EffectState = <T extends object = {}>(x: T) => T & Tag<'PainterState'> type EffectState = <T extends object = {}>(x: T) => T & Tag<'PainterState'>
const effectState: EffectState = x => ({_tag: 'PainterState', ...x}) const effectState: EffectState = x => ({_tag: 'PainterState', ...x})
export { export { type PainterEffect, task }
type EffectState as PainterState,
effectState as tagState, //
exit, // testing
type PainterEffect, //
type PainterTask,
task, type TestEffect = (x: PainterTask<{message: Option<string>}>) => PainterTask<
{message: Option<string>}
>
const testEffect: PainterEffect<{message: string, counter: number}> = x => {
const state = DoOption.start()
.bind('state', x.task.state)
.doL(ctx => {
console.log('Message:', ctx.state.message)
return some(undefined)
})
.doL(ctx => {
console.log('Counter:', ctx.state.counter)
return some(undefined)
})
.return(ctx =>
(ctx.state.counter < 100000)
? {...ctx.state, counter: ctx.state.counter + 1}
: none
)
if (pipe(state, getOrElse(none), hasTag('None'))) return {_tag: 'PainterExit'}
return task(x.task.origin.value, x.task.end.value)(
x.task.effect,
getOrElse(none)(state),
)
} }
const textTask = task<{message: string, counter: number}>(
cursorPos(2)(0),
cursorPos(4)(0),
)(
testEffect,
{
_tag: 'PainterState',
message: 'test message',
counter: 1,
},
)
const testFn = (x: PainterTask | PainterExit) => {
return hasTag('PainterExit')(x) ? 'Exit' : testFn(x.task.effect(x))
}
testFn(textTask)