wip interfaces
This commit is contained in:
parent
38343d7ec0
commit
1e09ca655f
3 changed files with 79 additions and 59 deletions
|
@ -141,13 +141,14 @@ class Method {
|
||||||
* @param {Function} target
|
* @param {Function} target
|
||||||
*/
|
*/
|
||||||
implement(builder, target) {
|
implement(builder, target) {
|
||||||
|
|
||||||
const impl = this.#implementation || this._defaultImplementation(builder.name)
|
const impl = this.#implementation || this._defaultImplementation(builder.name)
|
||||||
|
|
||||||
this._getInstallationPoint(target)[this.#name] = impl
|
this._getInstallationPoint(target)[this.#name] = impl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Implementations = Symbol()
|
||||||
|
|
||||||
class Interface {
|
class Interface {
|
||||||
#name
|
#name
|
||||||
|
|
||||||
|
@ -166,6 +167,27 @@ class Interface {
|
||||||
return this.#name
|
return this.#name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
findInterfaces() {
|
||||||
|
let interfaces = new Set()
|
||||||
|
let current = Object.getPrototypeOf(this)
|
||||||
|
console.log(current)
|
||||||
|
|
||||||
|
while (current != null) {
|
||||||
|
interfaces = new Set(current[Implementations])
|
||||||
|
current = Object.getPrototypeOf(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
return interfaces
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {{ name: string }} type
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
implementedBy(type) {
|
||||||
|
return this.findInterfaces().has(type)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {...(PropertyKey | Method)} methods
|
* @param {...(PropertyKey | Method)} methods
|
||||||
* @returns {this}
|
* @returns {this}
|
||||||
|
@ -200,23 +222,24 @@ class Interface {
|
||||||
* @param {FunctionConstructor} base
|
* @param {FunctionConstructor} base
|
||||||
*/
|
*/
|
||||||
build(base) {
|
build(base) {
|
||||||
const interfaces = [...this.#interfaces.values()].map(x => x.intoWrapper())
|
const interfaces = [...this.#interfaces.values()]
|
||||||
|
const wrappers = interfaces.map(x => x.intoWrapper())
|
||||||
|
|
||||||
const Interfaces = mix(base).with(...interfaces)
|
const Interfaces = mix(base).with(...wrappers)
|
||||||
|
|
||||||
const Algebra = class extends Interfaces { }
|
//const Algebra = class extends Interfaces { }
|
||||||
|
|
||||||
for (const method of this.#methods) {
|
for (const method of this.#methods) {
|
||||||
method.implement(this, Algebra)
|
method.implement(this, Interfaces)
|
||||||
}
|
}
|
||||||
|
|
||||||
return Algebra
|
Interfaces.prototype[Implementations] = new Set([...interfaces])
|
||||||
|
|
||||||
|
return Interfaces
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @template T */
|
export class BaseSet { }
|
||||||
export class BaseSet {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {PropertyKey} key
|
* @param {PropertyKey} key
|
||||||
|
|
|
@ -19,6 +19,9 @@ export class Ok extends Algebra(Setoid, Monad, Foldable) {
|
||||||
this.#value = value
|
this.#value = value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Ok<T, E>} other
|
||||||
|
*/
|
||||||
equals(other) {
|
equals(other) {
|
||||||
return other instanceof Ok &&
|
return other instanceof Ok &&
|
||||||
other.chain(v => v === this.#value)
|
other.chain(v => v === this.#value)
|
||||||
|
|
|
@ -1,74 +1,68 @@
|
||||||
|
// @ts-nocheck
|
||||||
import { it, assert } from 'folktest'
|
import { it, assert } from 'folktest'
|
||||||
import { Option, Result } from '../../src/index.js'
|
import { Option, Result } from '../../src/index.js'
|
||||||
|
import { Chain, Ord, Setoid } from '../../src/algebra/interfaces.js'
|
||||||
|
|
||||||
const Monads = [Option, Result]
|
const Algebra = [Option, Result]
|
||||||
|
|
||||||
const leftIdentity = (M, a, f) => {
|
const inc = x => F.of(x + 1)
|
||||||
assert(M(a).chain(f).equals(f(a)))
|
const dbl = x => F.of(x * 2)
|
||||||
}
|
|
||||||
|
|
||||||
const rightIdentity = (M, m) => {
|
const impl = i => m => i.implementedBy(m)
|
||||||
assert(m.chain(M).equals(m))
|
|
||||||
}
|
|
||||||
|
|
||||||
const associativity = (m, f, g) => {
|
|
||||||
assert(m.chain(f).chain(g).equals(m.chain(x => f(x).chain(g))))
|
|
||||||
}
|
|
||||||
|
|
||||||
export const prove = (M, m, a, f, g) => {
|
|
||||||
leftIdentity(M, a, f)
|
|
||||||
rightIdentity(M, m)
|
|
||||||
associativity(m, f, g)
|
|
||||||
}
|
|
||||||
|
|
||||||
const inc = F => x => F.of(x + 1)
|
|
||||||
const dbl = F => x => F.of(x * 2)
|
|
||||||
|
|
||||||
export const Tests = [
|
export const Tests = [
|
||||||
it('unit is a left identity', () => {
|
it('unit is a left identity', () => {
|
||||||
Monads.forEach(monad => {
|
console.log(Chain.implementedBy(Result))
|
||||||
const f = inc(monad)
|
Algebra.filter(impl(Chain)).forEach(algebra => {
|
||||||
// NOTE: okay but like, shut up
|
assert(
|
||||||
// @ts-ignore
|
algebra.of(1).chain(inc) == inc(1),
|
||||||
assert(monad.of(1).chain(f).equals(f(1)))
|
`${algebra.name} is not a left identity`
|
||||||
|
)
|
||||||
})
|
})
|
||||||
//prove(
|
|
||||||
// Ctr, M
|
|
||||||
// Ctr(1), m
|
|
||||||
// 1, a
|
|
||||||
// x => Ctr(x + 1), f
|
|
||||||
// x => Ctr(x * 2) g
|
|
||||||
//)
|
|
||||||
}),
|
}),
|
||||||
|
|
||||||
it('unit is a right identity', () => {
|
it('unit is a right identity', () => {
|
||||||
Monads.forEach(monad => {
|
Algebra.filter(impl(Chain)).forEach(algebra => {
|
||||||
const m = monad.of(1)
|
const m = algebra.of(1)
|
||||||
|
|
||||||
assert(
|
assert(
|
||||||
// NOTE: i heard this one already
|
m.chain(algebra.of).equals(m),
|
||||||
// @ts-ignore
|
`${algebra.name} is not a right identity`
|
||||||
m.chain(monad.of).equals(m)
|
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
|
|
||||||
it('unit is associative', () => {
|
it('unit is associative', () => {
|
||||||
Monads.forEach(monad => {
|
Algebra.filter(impl(Chain)).forEach(algebra => {
|
||||||
const m = monad.of(1)
|
const a = algebra.of(1)
|
||||||
const f = inc(monad)
|
|
||||||
const g = dbl(monad)
|
|
||||||
console.log(m.chain(f))
|
|
||||||
|
|
||||||
// NOTE: it was better the first time
|
const x = a.chain(inc).chain(dbl)
|
||||||
// @ts-ignore
|
const y = a.chain(x => inc(x).chain(dbl))
|
||||||
const x = m.chain(f).chain(g)
|
|
||||||
// @ts-ignore
|
|
||||||
const y = m.chain(x => f(x).chain(g))
|
|
||||||
|
|
||||||
assert(
|
assert(x == y, `${algebra.name} is not associative`)
|
||||||
x.equals(y)
|
})
|
||||||
)
|
}),
|
||||||
|
|
||||||
|
it('unit is reflexive', () => {
|
||||||
|
Algebra.filter(impl(Setoid)).forEach(algebra => {
|
||||||
|
const a = algebra.of(1)
|
||||||
|
assert(a.equals(a), `${algebra.name} is not reflexive`)
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
|
||||||
|
it('unit is symmetrical', () => {
|
||||||
|
Algebra.filter(impl(Setoid)).forEach(algebra => {
|
||||||
|
const a = algebra.of(1)
|
||||||
|
const b = algebra.of(1)
|
||||||
|
assert(a.equals(b) && b.equals(a), `${algebra.name} is not symmetrical`)
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
|
||||||
|
it('unit is antisymmetrical', () => {
|
||||||
|
Algebra.filter(impl(Ord)).forEach(algebra => {
|
||||||
|
const a = algebra.of(1)
|
||||||
|
const b = algebra.of(1)
|
||||||
|
assert(a.lte(b) && b.lte(a) && a.equals(b))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
]
|
]
|
||||||
|
|
Loading…
Add table
Reference in a new issue