Skip to content

Instantly share code, notes, and snippets.

@homam
Last active June 28, 2016 23:54
Show Gist options
  • Save homam/6274ca0ae81b45573ed3e6c98b1d2ece to your computer and use it in GitHub Desktop.
Save homam/6274ca0ae81b45573ed3e6c98b1d2ece to your computer and use it in GitHub Desktop.
const trace = (x, y) => {
console.log(x)
return y
}
const trace1 = x => trace(x, x)
const id = x => x
const swap = ([x, y]) => [y, x]
// before . f . after
// Arrow a => (x -> b) -> (y -> b) -> (x -> m y) -> a x b
const wrap1 = (arrow, before, after, f) =>
arrow.arr(before).pipe(arrow.arrM(f)).pipe(arrow.arr(after))
// same as wrap1
// Arrow a => (x -> b) -> (y -> b) -> (x -> m y) -> a x b
const wrap12 = (arrow, before, after, f) => new arrow(x => {
let b = arrow.arr(before).run(x)
let y = arrow.arrM(id).pipe(arrow.arrM(f)).run(b)
return arrow.arrM(id).pipe(arrow.arr(after)).run(y)
})
// λ x ->
// b <- liftM before x
// y <- f x
// _ <- liftM after [b, y]
// return y
// Arrow a => (x -> b) -> ([b, x] -> ()) -> (x -> m y) -> a x y
const wrap2 = (arrow, before, after, f) =>
arrow.arr(before)
.fanout(arrow.arrM(f))
.pipe(
arrow.arr(([x, y]) => { after([x, y]); return y })
)
class Arrow {
constructor(T) {
// a b c -> a b' c' -> a (b,b') (c,c')
this.split = g => this.first().pipe(T.arr(swap)).pipe(g.first()).pipe(T.arr(swap))
// a b c -> a b c' -> a b (c,c')
this.fanout = g => T.arr(b => [b, b]).pipe(this.split(g))
}
}
class Func extends Arrow {
constructor(f) {
super(Func)
// a b c -> a c d -> a b d
this.pipe = g => new Func(x => g.run(this.run(x)))
// a b c -> a (b,d) (c,d)
this.first = _ => new Func(([x, y]) => [f(x), y])
this.run = x => f(x)
}
}
// x => a x x
Func.id = new Func(x => x)
// (x -> y) -> a x y
Func.arr = f => new Func(f)
// (x -> m y) -> a x y
Func.arrM = f => new Func(f)
// try arrows for fun :)
//console.log(new Func(x => 2 * x).first().run([2, 33]))
//console.log(new Func(x => 2 * x).split(new Func(x => x * 10)).run([2, 33]))
//console.log(new Func(x => 2 * x).fanout(new Func(x => x * 10)).run(3))
console.log(
wrap12(Func,
x => x*2,
x => x+1,
x => x * x / 2
).run(3)
)
console.log(wrap2(Func,
x => Date.now(),
([b, y]) =>
console.log(`${y} produced after ${Date.now() - b}`)
,
x => x * 10
).run(3))
class Prom extends Arrow {
constructor(f) {
super(Prom)
// a b c -> a c d -> a b d
this.pipe = g => new Prom(x => this.run(x).then(y => g.run(y))) // then = >>=
// a b c -> a (b,d) (c,d)
this.first = _ => new Prom(([x, y]) => this.run(x).then(x => [x, y])) // then = fmap
this.run = x => f(x)
}
}
// x => a x x
Prom.id = new Prom(x => Promise.resolve(x))
// (x -> y) -> a x y
Prom.arr = f => new Prom(x => Promise.resolve(f(x)))
// (x -> m y) -> a x y
Prom.arrM = f => new Prom(f)
wrap2(Prom,
x => Date.now(),
([b, y]) =>
console.log(`${y} produced after ${Date.now() - b}`)
,
x => new Promise(res => setTimeout(_ => res(x * x / 2), 1000))
).run(3)
.then(x => console.log(`P = ${x}`))
const trace = (x, y) => {
console.log(x)
return y
}
const trace1 = x => trace(x, x)
const id = x => x
const swap = ([x, y]) => [y, x]
// before . f . after
// Arrow a => (x -> b) -> (y -> b) -> (x -> m y) -> a x b
const wrap1 = (arrow, before, after, f) =>
arrow.arr(before).pipe(arrow.arrM(f)).pipe(arrow.arr(after))
// same as wrap1
// Arrow a => (x -> b) -> (y -> b) -> (x -> m y) -> a x b
const wrap12 = (arrow, before, after, f) => new arrow(x => {
let b = arrow.arr(before).run(x)
let y = arrow.arrM(id).pipe(arrow.arrM(f)).run(b)
return arrow.arrM(id).pipe(arrow.arr(after)).run(y)
})
// λ x ->
// let b = before x
// y <- f x
// let a = after [b, y]
// return y
// Arrow a => (x -> b) -> ([b, x] -> ()) -> (x -> m y) -> a x y
const wrap2 = (arrow, before, after, f) =>
arrow.arr(before)
.fanout(arrow.arrM(f))
.pipe(
arrow.arr(([x, y]) => { after([x, y]); return y })
)
const wrap3 = (arrow, before, after, f) => x => new arrow(y => {
let b = before(y)
return liftM(arrow, f).map(y => {
after([b, y])
return y
}).run(x)
}).run(x)
class Arrow {
constructor(T) {
// a b c -> a b' c' -> a (b,b') (c,c')
this.split = g => this.first().pipe(T.arr(swap)).pipe(g.first()).pipe(T.arr(swap))
// a b c -> a b c' -> a b (c,c')
this.fanout = g => T.arr(b => [b, b]).pipe(this.split(g))
}
}
const liftM = (arrow, f) => arrow.pure(f)
class Func extends Arrow {
constructor(f) {
super(Func)
this.map = g => new Func(x => g(this.run(x)))
this.bind = g => g(this.run(x))
// a b c -> a c d -> a b d
this.pipe = g => new Func(x => g.run(this.run(x)))
// a b c -> a (b,d) (c,d)
this.first = _ => new Func(([x, y]) => [f(x), y])
this.run = x => f(x)
}
}
Func.pure = x => new Func(x)
// x => a x x
Func.id = new Func(x => x)
// (x -> y) -> a x y
Func.arr = f => new Func(f)
// (x -> m y) -> a x y
Func.arrM = f => new Func(f)
Func.pure(id).map(x => x *3).run(4)
class Prom extends Arrow {
constructor(f) {
super(Prom)
this.map = g => new Prom(x => this.run(x).then(g)) // then = >>=
this.bind = g => new Prom(x => this.run(x).then(g)) // then = >>=
// a b c -> a c d -> a b d
this.pipe = g => new Prom(x => this.run(x).then(y => g.run(y))) // then = >>=
// a b c -> a (b,d) (c,d)
this.first = _ => new Prom(([x, y]) => this.run(x).then(x => [x, y])) // then = fmap
this.run = x => f(x)
}
}
Prom.pure = x => new Prom(x)
// x => a x x
Prom.id = new Prom(x => Promise.resolve(x))
// (x -> y) -> a x y
Prom.arr = f => new Prom(x => Promise.resolve(f(x)))
// (x -> m y) -> a x y
Prom.arrM = f => new Prom(f)
console.log(wrap3(Func,
x => Date.now(),
([b, y]) => {
console.log(`${y} produced after ${Date.now() - b}`)
},
x => x * 10
)(3))
wrap3(Prom,
x => Date.now(),
([b, y]) => {
console.log(`${y} produced after ${Date.now() - b}`)
},
x => new Promise(res => setTimeout(_ => res(x * x / 2), 1000))
)(3)
.then(x => console.log(`P = ${x}`))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment