Last active
December 30, 2024 13:00
-
-
Save titouancreach/0607039a20d71131f1db6aa824f5da9f to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export type Free<F, A> = Pure<A> | FreeF<F, A>; | |
export class Pure<A> { | |
readonly _tag = "Pure" as const; | |
constructor(public readonly value: A) {} | |
} | |
export class FreeF<F, A> { | |
readonly _tag = "FreeF" as const; | |
constructor( | |
public readonly effect: F, | |
public readonly next: <B>(value: B) => Free<F, A>, | |
) {} | |
} | |
export function pure<F, A>(value: A): Free<F, A> { | |
return new Pure(value); | |
} | |
export function free<F, A>(effect: F): Free<F, A> { | |
// biome-ignore lint/suspicious/noExplicitAny: <explanation> | |
return new FreeF(effect, (value) => pure(value as any as A)); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Cancel } from "@repo/shared/src/Cancel"; | |
import { Free, free, pure } from "../Free"; | |
import { Confirmation } from "./UI/Confirmation"; | |
import { AskForReason, CancelReason } from "./UI/Cancel"; | |
type CancelActions<A> = | |
| { | |
_tag: "Confirmation"; | |
next: () => Free<CancelActions<A>, A>; | |
} | |
| { | |
_tag: "AskReason"; | |
next: (reason: typeof CancelReason.Type) => Free<CancelActions<A>, A>; | |
}; | |
export function confirme<A>(next: () => Free<CancelActions<A>, A>): CancelActions<A> { | |
return { _tag: "Confirmation", next: next }; | |
} | |
export function askReason( | |
next: (reason: typeof CancelReason.Type) => Free<CancelActions<Cancel>, Cancel>, | |
): CancelActions<Cancel> { | |
return { _tag: "AskReason", next }; | |
} | |
export const InterpretComponent = ({ | |
effect, | |
onResult, | |
goBack, | |
}: { | |
onResult: <T>(value: T) => void; | |
effect: CancelActions<Cancel>; | |
goBack: () => void; | |
}) => { | |
switch (effect._tag) { | |
case "AskReason": | |
return <AskForReason onResult={onResult} />; | |
case "Confirmation": | |
return ( | |
<Confirmation | |
text="Are you sure to cancel ?" | |
onConfirm={() => onResult(undefined)} | |
goBack={goBack} | |
/> | |
); | |
} | |
}; | |
export const program = (_: unknown) => | |
free<CancelActions<Cancel>, Cancel>( | |
askReason((reason) => | |
free( | |
confirme(() => | |
pure( | |
new Cancel({ | |
reason: reason, | |
}), | |
), | |
), | |
), | |
), | |
); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { useState } from "react"; | |
import { Free } from "./Free"; | |
// biome-ignore lint/suspicious/noExplicitAny: <explanation> | |
export const ProgramRunner = <Effect extends { next: (x: any) => Free<Effect, Value> }, Value>({ | |
program, | |
onComplete, | |
interpretComponents: Interpret, | |
}: { | |
program: Free<Effect, Value>; | |
onComplete: (result: Value) => void; | |
interpretComponents: React.FC<{ effect: Effect; goBack: () => void; onResult: <T>(value: T) => void }>; | |
}) => { | |
const [programHistory, setHistory] = useState<Array<Free<Effect, Value>>>([]); | |
const goBack = () => { | |
const [previousProgram, ...rest] = programHistorique; | |
setHistorique(rest); | |
setCurrentProgram(previousProgram as Free<Effect, Value>); | |
}; | |
const [currentProgram, setCurrentProgram] = useState(program); | |
const handleResult = <T,>(value: T) => { | |
if (currentProgram._tag === "Pure") { | |
onComplete(currentProgram.value); | |
return; | |
} | |
const nextStep = currentProgram.effect.next(value); | |
if (nextStep._tag === "Pure") { | |
onComplete(nextStep.value); | |
} else { | |
setCurrentProgram(nextStep); | |
setHistory([currentProgram, ...programHistorique]); | |
} | |
}; | |
if (currentProgram._tag === "Pure") { | |
onComplete(currentProgram.value); | |
return null; | |
} | |
return <Interpret effect={currentProgram.effect} onResult={handleResult} revenirEnArriere={revenirEnArriere} />; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment