Skip to content

Instantly share code, notes, and snippets.

@md2perpe
Created February 21, 2021 22:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save md2perpe/71e3dcf22360195a23846f9808583832 to your computer and use it in GitHub Desktop.
Save md2perpe/71e3dcf22360195a23846f9808583832 to your computer and use it in GitHub Desktop.
Monads
interface Thenable<a> {
then<b>(cont: (_: a) => Thenable<b>): Thenable<b>;
}
/*
run_slow_task.then((result) => {
do_something(result).then((new_result) => {
do_something_else(new_result)
})
})
*/
declare function run_slow_task<a>(): Thenable<a>;
declare function do_something<a,b>(result: a): Thenable<b>;
declare function do_something_else<b,c>(new_result: b): Thenable<c>;
/*
function main<c>(): Thenable<c> {
return run_slow_task().then((result) => {
return do_something(result).then((new_result) => {
return do_something_else(new_result)
})
})
}
*/
async function main() {
const result = await run_slow_task();
const new_result = await do_something(result);
const final_result = await do_something_else(new_result);
return final_result;
}
function foo(n: number): Promise<number>
{
return new Promise((resolve, reject) => {
if (n % 2 == 0) {
resolve(n);
}
else {
reject("not even");
}
})
}
class MyArray<T> implements Thenable<T>
{
private array: T[];
constructor(array: T[]) {
this.array = array;
}
then<S>(cont: (value: T) => MyArray<S>): MyArray<S> {
let array_of_MyArray = this.array.map(cont);
let result = [];
for (let a of array_of_MyArray) {
result.push(...a.array);
}
return new MyArray(result);
}
}
function main2()
{
return new MyArray([1, 2, 3]).then((n) => {
return new MyArray([2*n, 2*n+1]);
})
}
/*
async function main2()
{
const n = await new MyArray([1,2,3]);
return await new MyArray([2*n,2*n+1]);
}
*/
//console.log(main2())
abstract class Maybe<T> implements Thenable<T>
{
abstract then<S>(cont: (_: T) => Maybe<S>): Maybe<S>;
static give<S>(value: S): Maybe<S> {
return new Just<S>(value);
}
}
class Just<T> extends Maybe<T>
{
private value: T;
constructor(value: T) {
super();
this.value = value;
}
then<S>(cont: (_: T) => Maybe<S>): Maybe<S> {
return cont(this.value);
}
}
class Nothing<T> extends Maybe<T>
{
constructor() {
super();
}
then<S>(cont: (_: T) => Maybe<S>): Maybe<S> {
return new Nothing<S>();
}
}
function div(x: number, y: number): Maybe<number>
{
if (y == 0) {
return new Nothing();
}
return new Just(x/y);
}
function main3()
{
let X = Maybe.give(2);
let Y = Maybe.give(0);
let Z = Maybe.give(5);
return (
X.then(x => // X >>= \x -> // x <- X
Y.then(y => // Y >>= \y -> // y <- Y
Z.then(z => // Z >>= \z -> // z <- Z
div(x, y).then(w => // div x y >>= \w -> // w <- div x y
div(w, z) // div w z // div w z
)))))
}
console.log(main3())
class ContinuationMonad<r,a> implements Thenable<a>
{
// private continuation((_: a) => r): r;
private continuation: (_: (_: a) => r) => r;
constructor(continuation: (_: (_: a) => r) => r) {
this.continuation = continuation;
}
static give<r,a>(value: a) {
return new ContinuationMonad<r,a>(
(then: (_: a) => r) => then(value)
);
}
then<b>(next: (_: a) => ContinuationMonad<r,b>): ContinuationMonad<r,b> {
// this.continuation: (_: (_: a) => r) => r
return new ContinuationMonad(
(c: (_: b) => r) => this.continuation(
(value: a) => next(value).continuation(c)
)
);
}
run(handler: (_: a) => r): r {
return this.continuation(handler);
}
}
function main4()
{
let cm = (
ContinuationMonad.give(42) .then((x: number) =>
ContinuationMonad.give(x+13) .then((y: number) =>
ContinuationMonad.give(y/5)
)));
cm.run(console.log);
}
main4();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment