Created
October 29, 2024 16:49
-
-
Save zoedsoupe/f5cb4f67b8b4d1e81fa1768d7dc56063 to your computer and use it in GitHub Desktop.
Implementação de mônadas úteis em TypeScript
This file contains 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
// Definição da Either Monad | |
type Either<L, R> = Left<L> | Right<R>; | |
type Left<L> = { kind: 'left'; value: L }; | |
type Right<R> = { kind: 'right'; value: R }; | |
function left<L, R>(value: L): Either<L, R> { | |
return { kind: 'left', value }; | |
} | |
function right<L, R>(value: R): Either<L, R> { | |
return { kind: 'right', value }; | |
} | |
// Função bind para encadear computações via Either | |
function bind<L, R, R2>( | |
either: Either<L, R>, | |
func: (value: R) => Either<L, R2> | |
): Either<L, R2> { | |
return either.kind === 'right' ? func(either.value) : either; | |
} | |
// Exemplo de uso da Either | |
function parseNumber(str: string): Either<string, number> { | |
const num = Number(str); | |
return isNaN(num) ? left('Not a number') : right(num); | |
} | |
function reciprocal(num: number): Either<string, number> { | |
return num === 0 ? left('Division by zero') : right(1 / num); | |
} | |
const result = bind(parseNumber('5'), reciprocal); | |
// Resultado: right(0.2) | |
// Definição da State Monad | |
type State<S, A> = (state: S) => [A, S]; | |
function stateOf<S, A>(value: A): State<S, A> { | |
return (state) => [value, state]; | |
} | |
// Encadear computações via State | |
function bind<S, A, B>( | |
stateFunc: State<S, A>, | |
func: (value: A) => State<S, B> | |
): State<S, B> { | |
return (state) => { | |
const [a, newState] = stateFunc(state); | |
return func(a)(newState); | |
}; | |
} | |
// Exemplo de uso da State! bem parecida com React `useState`, quem diria né? | |
function increment(): State<number, void> { | |
return (state) => [undefined, state + 1]; | |
} | |
function getState<S>(): State<S, S> { | |
return (state) => [state, state]; | |
} | |
const program = bind(increment(), () => | |
bind(increment(), () => getState<number>()) | |
); | |
const [result, finalState] = program(0); | |
// finalState: 2 | |
// Definição da Writer Monad | |
type Writer<W, A> = { value: A; log: W[] }; | |
function writerOf<W, A>(value: A): Writer<W, A> { | |
return { value, log: [] }; | |
} | |
// Encadear operaçõe via Writer | |
function bind<W, A, B>( | |
writer: Writer<W, A>, | |
func: (value: A) => Writer<W, B> | |
): Writer<W, B> { | |
const result = func(writer.value); | |
return { value: result.value, log: writer.log.concat(result.log) }; | |
} | |
function tell<W>(message: W): Writer<W, void> { | |
return { value: undefined, log: [message] }; | |
} | |
function compute(x: number): Writer<string, number> { | |
return bind(tell(`Starting with ${x}`), () => { | |
const result = x * 2; | |
return bind(tell(`Doubled to ${result}`), () => writerOf(result)); | |
}); | |
} | |
const result = compute(5); | |
// result.value: 10 | |
// result.log: ['Starting with 5', 'Doubled to 10'] | |
// Definição da Option Monad | |
type Option<A> = Some<A> | None; | |
type Some<A> = { kind: 'some'; value: A }; | |
type None = { kind: 'none' }; | |
function some<A>(value: A): Option<A> { | |
return { kind: 'some', value }; | |
} | |
const none: Option<never> = { kind: 'none' }; | |
// Encadear computações via Option | |
function bind<A, B>( | |
option: Option<A>, | |
func: (value: A) => Option<B> | |
): Option<B> { | |
return option.kind === 'some' ? func(option.value) : none; | |
} | |
// Exemplos de uso | |
function safeDivide(a: number, b: number): Option<number> { | |
return b === 0 ? none : some(a / b); | |
} | |
const result = bind(some(10), (x) => safeDivide(x, 2)); | |
// result: some(5) | |
// Promise já é nativo do JS/TS, então a operação de bind é meio redundante | |
// As Promises já são uma mônada nativa em JavaScript/TypeScript | |
function bind<A, B>( | |
promise: Promise<A>, | |
func: (value: A) => Promise<B> | |
): Promise<B> { | |
return promise.then(func); | |
} | |
// Exemplo de uso | |
function fetchData(url: string): Promise<string> { | |
return fetch(url).then((res) => res.text()); | |
} | |
const result = bind(fetchData('https://example.com'), (data) => { | |
console.log(data); | |
return Promise.resolve('Done'); | |
}); | |
// Imprime o conteúdo e retorna 'Done' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment