refactor: change onType to match and take only one pattern and result
All checks were successful
/ test (pull_request) Successful in 17s
All checks were successful
/ test (pull_request) Successful in 17s
This commit is contained in:
parent
491e207fad
commit
92e232e06d
22 changed files with 147 additions and 135 deletions
|
@ -1,14 +1,14 @@
|
|||
import {BooleanT} from './BooleanT.js'
|
||||
import {onType} from '#core/helpers.js'
|
||||
import {match} from '#core/helpers.js'
|
||||
import {Returns, Type, TypeOfTypes, Undefined} from '#core/Type.js'
|
||||
import {NumberT} from '#number/NumberT.js'
|
||||
|
||||
const bool = f => Returns(BooleanT, f)
|
||||
|
||||
export const boolean = onType(
|
||||
BooleanT, bool(p => p),
|
||||
NumberT, bool(a => !!a),
|
||||
TypeOfTypes, bool(() => true),
|
||||
Undefined, bool(() => false),
|
||||
[], bool(() => false)
|
||||
)
|
||||
export const boolean = [
|
||||
match(BooleanT, bool(p => p)),
|
||||
match(NumberT, bool(a => !!a)),
|
||||
match(TypeOfTypes, bool(() => true)),
|
||||
match(Undefined, bool(() => false)),
|
||||
match([], bool(() => false))
|
||||
]
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import {Type} from '#core/Type.js'
|
||||
import {onType} from '#core/helpers.js'
|
||||
import {match} from '#core/helpers.js'
|
||||
|
||||
const isComplex = z => z && typeof z === 'object' && 're' in z && 'im' in z
|
||||
|
||||
|
@ -10,15 +10,17 @@ function complexSpecialize(ComponentType) {
|
|||
const specTest = z => isComplex(z) && compTest(z.re) && compTest(z.im)
|
||||
const typeName = `Complex(${ComponentType})`
|
||||
if (ComponentType.concrete) {
|
||||
const fromSpec = [
|
||||
ComponentType, math => r => ({re: r, im: ComponentType.zero})]
|
||||
for (const [matchType, fctry] of ComponentType.from.patterns) {
|
||||
fromSpec.push(this.specialize(matchType.type), math => {
|
||||
const compConv = fctry(math)
|
||||
return z => ({re: compConv(z.re), im: compConv(z.im)})
|
||||
})
|
||||
const fromSpec = [match(
|
||||
ComponentType, math => r => ({re: r, im: ComponentType.zero}))]
|
||||
for (const {pattern, does} of ComponentType.from) {
|
||||
fromSpec.push(match(
|
||||
this.specialize(pattern.type),
|
||||
math => {
|
||||
const compConv = does(math)
|
||||
return z => ({re: compConv(z.re), im: compConv(z.im)})
|
||||
}))
|
||||
}
|
||||
const typeOptions = {from: onType(...fromSpec), typeName}
|
||||
const typeOptions = {from: fromSpec, typeName}
|
||||
if ('zero' in ComponentType) {
|
||||
typeOptions.zero = {re: ComponentType.zero, im: ComponentType.zero}
|
||||
if ('one' in ComponentType) {
|
||||
|
|
|
@ -21,11 +21,11 @@ describe('Complex Type', () => {
|
|||
const convertImps = CplxNum.from
|
||||
let cnvNtoCN
|
||||
let cnvCBtoCN
|
||||
for (const [pattern, convFactory] of convertImps.patterns) {
|
||||
for (const {pattern, does} of convertImps) {
|
||||
if (pattern.match([NumberT])[0] === 1) {
|
||||
cnvNtoCN = convFactory(math)
|
||||
cnvNtoCN = does(math)
|
||||
} else if (pattern.match([Complex(BooleanT)])[0] === 1) {
|
||||
cnvCBtoCN = convFactory(math)
|
||||
cnvCBtoCN = does(math)
|
||||
}
|
||||
}
|
||||
assert.deepStrictEqual(cnvNtoCN(3.5), {re: 3.5, im: 0})
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import {Complex} from './Complex.js'
|
||||
import {onType} from "#core/helpers.js"
|
||||
import {match} from "#core/helpers.js"
|
||||
import {Returns} from "#core/Type.js"
|
||||
import {Any} from "#core/TypePatterns.js"
|
||||
|
||||
export const complex = onType(
|
||||
Any, (math, T) => {
|
||||
export const complex = [
|
||||
match(Any, (math, T) => {
|
||||
const z = math.zero(T)
|
||||
if (math.hasnan(T)) {
|
||||
const isnan = math.isnan.resolve([T])
|
||||
|
@ -15,8 +15,8 @@ export const complex = onType(
|
|||
})
|
||||
}
|
||||
return Returns(Complex(T), r => ({re: r, im: z}))
|
||||
},
|
||||
[Any, Any], (math, [T, U]) => {
|
||||
}),
|
||||
match([Any, Any], (math, [T, U]) => {
|
||||
if (T !== U) {
|
||||
throw new RangeError(
|
||||
'mixed complex types disallowed '
|
||||
|
@ -24,5 +24,4 @@ export const complex = onType(
|
|||
}
|
||||
return Returns(Complex(T), (r, m) => ({re: r, im: m}))
|
||||
})
|
||||
|
||||
|
||||
]
|
||||
|
|
|
@ -21,7 +21,10 @@ export class Type extends Function {
|
|||
})
|
||||
|
||||
this.test = f
|
||||
this.from = options.from ?? {patterns: []} // mock empty Implementations
|
||||
// we want property `from` to end up as an array of Matchers:
|
||||
this.from = options.from
|
||||
? Array.isArray(options.from) ? options.from : [options.from]
|
||||
: []
|
||||
if ('zero' in options) this.zero = options.zero
|
||||
if ('one' in options) this.one = options.one
|
||||
if ('nan' in options) this.nan = options.nan
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import ArrayKeyedMap from 'array-keyed-map'
|
||||
|
||||
import {
|
||||
Implementations, ImplementationsGenerator, ResolutionError,
|
||||
isPlainFunction, isPlainObject, onType, types
|
||||
Implementations, ImplementationsGenerator, Matcher, ResolutionError,
|
||||
isPlainFunction, isPlainObject, match, types
|
||||
} from './helpers.js'
|
||||
import {bootstrapTypes, Returns, whichType, Type} from './Type.js'
|
||||
import {matched, needsCollection, Passthru} from './TypePatterns.js'
|
||||
|
@ -45,11 +45,14 @@ export class TypeDispatcher {
|
|||
// an Implementations that associates it with the Passthru pattern
|
||||
// -- a factory for entities, to be invoked to get the value of a key
|
||||
// for any types. You can just merge that.
|
||||
// -- a value or behavior that applies just when the types of an
|
||||
// argument match a type pattern. For that, you merge the result
|
||||
// of `match(PATTERN, VALUE)`
|
||||
// -- a collection of different values, or different behaviors, or
|
||||
// different factories for different types for a given key. For that
|
||||
// you merge an Implementations object that associates each item with
|
||||
// a TypePattern. An Implementation object can most easily be
|
||||
// generated with `onType(PATTERN, VALUE, PATTERN, VALUE,...)`
|
||||
// different factories for different lists of argument types for a
|
||||
// given key. For that you merge an array of results of `match`,
|
||||
// so something like
|
||||
// `[match(PATTERN, VALUE), match(PATTERN, VALUE), ...]`
|
||||
// Initially I thought those were all the possibilities. But then I
|
||||
// wanted to export something that when merged, would set the Passthru
|
||||
// pattern to a fresh specific object for that merge, but so that the
|
||||
|
@ -57,10 +60,10 @@ export class TypeDispatcher {
|
|||
// particular TypeDispatcher (this situation applies to the config object).
|
||||
// To produce that behavior, you need a fourth thing
|
||||
// -- an ImplementationGenerator, which is basically a function that
|
||||
// returns an Implementations object as above. As this is only needed
|
||||
// for a single entity that will be merged into multiple different
|
||||
// TypeDispatchers, there's not a big focus on making this convenient;
|
||||
// it's not expected to come up much.
|
||||
// returns one of the last couple of options above. As this variant is
|
||||
// only needed for a single entity that will be merged into multiple
|
||||
// different TypeDispatchers, there's not a big focus on making
|
||||
// specifying it convenient; it's not expected to come up much.
|
||||
|
||||
merge(spec) {
|
||||
if (!spec) return
|
||||
|
@ -74,9 +77,7 @@ export class TypeDispatcher {
|
|||
// For special cases like types, config, etc, we can wrap
|
||||
// a function in ImplementationsGenerator to produce the thing
|
||||
// we should really merge:
|
||||
if (val instanceof ImplementationsGenerator) {
|
||||
val = val.generate()
|
||||
}
|
||||
if (val instanceof ImplementationsGenerator) val = val.generate()
|
||||
|
||||
// Now dispatch on what sort of thing we are supposed to merge:
|
||||
if (val instanceof Type) {
|
||||
|
@ -100,7 +101,14 @@ export class TypeDispatcher {
|
|||
|
||||
// Everything else we coerce into Implementations and deal with
|
||||
// right here:
|
||||
if (!(val instanceof Implementations)) val = onType(Passthru, val)
|
||||
if (val instanceof Matcher) val = new Implementations(val)
|
||||
if (Array.isArray(val)) val = new Implementations(val)
|
||||
if (!(val instanceof Implementations)) {
|
||||
val = new Implementations(match(Passthru, val))
|
||||
}
|
||||
|
||||
// hereafter we may assume that val is an instance of Implementations
|
||||
|
||||
if (!(key in this)) {
|
||||
// Need to "bootstrap" the item:
|
||||
// We initially define it with a temporary getter, only
|
||||
|
@ -189,11 +197,11 @@ export class TypeDispatcher {
|
|||
this._behaviors[key] = new ArrayKeyedMap()
|
||||
}
|
||||
|
||||
// Now add all of the patterns of this implementation:
|
||||
for (const [pattern, result] of val.patterns) {
|
||||
// Now add all of the matchers of this Implementations:
|
||||
for (const {pattern, does} of val.matchers) {
|
||||
if (pattern === Passthru) {
|
||||
if (key in this._fallbacks) this._disengageFallback(key)
|
||||
this._fallbacks[key] = result
|
||||
this._fallbacks[key] = does
|
||||
} else {
|
||||
this._clearBehaviorsMatching(key, pattern)
|
||||
// if it happens the same pattern is already in the
|
||||
|
@ -201,7 +209,7 @@ export class TypeDispatcher {
|
|||
const imps = this._implementations[key]
|
||||
const have = imps.findIndex(elt => pattern.equal(elt[0]))
|
||||
if (have >= 0) imps.splice(have, 1)
|
||||
this._implementations[key].unshift([pattern, result])
|
||||
this._implementations[key].unshift([pattern, does])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ class MatchTypePattern extends TypePattern {
|
|||
if (position < typeSequence.length) {
|
||||
if (this.type.specializesTo(actual)) return [position + 1, actual]
|
||||
if (options.convert) {
|
||||
for (const [pattern, convertor] of this.type.from.patterns) {
|
||||
for (const {pattern, does: convertor} of this.type.from) {
|
||||
const [pos] = pattern.match([actual])
|
||||
if (pos === 1) {
|
||||
return [position + 1, {actual, convertor, matched: this.type}]
|
||||
|
|
|
@ -4,7 +4,7 @@ import * as booleans from '#boolean/all.js'
|
|||
import * as generics from '#generic/all.js'
|
||||
import * as numbers from '#number/all.js'
|
||||
import {NumberT} from '#number/NumberT.js'
|
||||
import {onType, ResolutionError} from "#core/helpers.js"
|
||||
import {match, ResolutionError} from "#core/helpers.js"
|
||||
import {Any} from "#core/TypePatterns.js"
|
||||
import {Returns, NotAType} from "#core/Type.js"
|
||||
import {plain} from "#number/helpers.js"
|
||||
|
@ -20,10 +20,10 @@ describe('TypeDispatcher', () => {
|
|||
assert.strictEqual(incremental.add(-1.5, 0.5), -1)
|
||||
assert.throws(() => incremental.add(7, undefined), ResolutionError)
|
||||
// Make Undefined act like zero:
|
||||
incremental.merge({add: onType(
|
||||
[Undefined, Any], (_m, [_U, T]) => Returns(T, (_a, b) => b),
|
||||
[Any, Undefined], (_m, [T]) => Returns(T, a => a)
|
||||
)})
|
||||
incremental.merge({add: [
|
||||
match([Undefined, Any], (_m, [_U, T]) => Returns(T, (_a, b) => b)),
|
||||
match([Any, Undefined], (_m, [T]) => Returns(T, a => a))
|
||||
]})
|
||||
assert.strictEqual(incremental.add(7, undefined), 7)
|
||||
assert.strictEqual(
|
||||
incremental.resolve('add', [TypeOfTypes, Undefined]).returns,
|
||||
|
@ -34,10 +34,10 @@ describe('TypeDispatcher', () => {
|
|||
NumberT)
|
||||
// Oops, changed my mind ;-), make it work like NaN with numbers:
|
||||
const alwaysNaN = Returns(NumberT, () => NaN)
|
||||
incremental.merge({add: onType(
|
||||
[Undefined, NumberT], alwaysNaN,
|
||||
[NumberT, Undefined], alwaysNaN
|
||||
)})
|
||||
incremental.merge({add: [
|
||||
match([Undefined, NumberT], alwaysNaN),
|
||||
match([NumberT, Undefined], alwaysNaN)
|
||||
]})
|
||||
assert(isNaN(incremental.add(undefined, -3.25)))
|
||||
assert.strictEqual(
|
||||
incremental.add.resolve([Undefined, NumberT]).returns,
|
||||
|
@ -61,7 +61,7 @@ describe('TypeDispatcher', () => {
|
|||
assert.strictEqual(bgn.negate(true), -1)
|
||||
assert(bgn._behaviors.negate.has([BooleanT]))
|
||||
const deps = bgn._dependencies.negate
|
||||
bgn.merge({number: onType([BooleanT], Returns(NumberT, b => b ? 2 : 0))})
|
||||
bgn.merge({number: match([BooleanT], Returns(NumberT, b => b ? 2 : 0))})
|
||||
assert(!bgn._behaviors.negate.has([BooleanT]))
|
||||
assert.strictEqual(bgn.negate(true), -2)
|
||||
})
|
||||
|
|
|
@ -1,16 +1,15 @@
|
|||
import assert from 'assert'
|
||||
import {
|
||||
Implementations, onType, isPlainObject, isPlainFunction
|
||||
Matcher, match, isPlainObject, isPlainFunction, Implementations
|
||||
} from '../helpers.js'
|
||||
import {Type, Undefined, TypeOfTypes} from '../Type.js'
|
||||
import {TypePattern} from '../TypePatterns.js'
|
||||
|
||||
describe('Core helpers', () => {
|
||||
it('defines what Implementations are', () => {
|
||||
const imps = onType(Undefined, 7, [TypeOfTypes, Undefined], -3)
|
||||
assert(imps instanceof Implementations)
|
||||
assert(imps.patterns instanceof Array)
|
||||
assert(imps.patterns.every(([k]) => k instanceof TypePattern))
|
||||
it('defines what Matchers are', () => {
|
||||
const matcher = match([TypeOfTypes, Undefined], -3)
|
||||
assert(matcher instanceof Matcher)
|
||||
assert(matcher.pattern instanceof TypePattern)
|
||||
})
|
||||
|
||||
it('detects plain objects', () => {
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
import {pattern, Passthru} from './TypePatterns.js'
|
||||
|
||||
export class Implementations {
|
||||
constructor(imps) {
|
||||
this.patterns = []
|
||||
this._add(imps)
|
||||
}
|
||||
_add(imps) {
|
||||
for (let i = 0; i < imps.length; ++i) {
|
||||
this.patterns.push([pattern(imps[i]), imps[++i]])
|
||||
}
|
||||
}
|
||||
also(...imps) {
|
||||
this._add(imps)
|
||||
export class Matcher {
|
||||
constructor(spec, facOrBehave) {
|
||||
this.pattern = pattern(spec)
|
||||
this.does = facOrBehave
|
||||
}
|
||||
}
|
||||
|
||||
export const onType = (...imps) => new Implementations(imps)
|
||||
export class Implementations {
|
||||
constructor(impOrImps) {
|
||||
if (Array.isArray(impOrImps)) {
|
||||
this.matchers = impOrImps
|
||||
} else this.matchers = [impOrImps]
|
||||
}
|
||||
}
|
||||
|
||||
export const match = (spec, facOrBehave) => new Matcher(spec, facOrBehave)
|
||||
|
||||
export class ImplementationsGenerator {
|
||||
constructor(f) {
|
||||
|
@ -34,7 +34,7 @@ export class ImplementationsGenerator {
|
|||
// collection of types (and modifying the types in one would affect them
|
||||
// all). Hence we do:
|
||||
|
||||
export const types = new ImplementationsGenerator(() => onType(Passthru, {}))
|
||||
export const types = new ImplementationsGenerator(() => match(Passthru, {}))
|
||||
|
||||
export class ResolutionError extends TypeError {
|
||||
constructor(...args) {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import {onType} from '#core/helpers.js'
|
||||
import {match} from '#core/helpers.js'
|
||||
import {TypeOfTypes, Undefined} from '#core/Type.js'
|
||||
import {boolnum} from '#number/helpers.js'
|
||||
|
||||
export const indistinguishable = onType(
|
||||
[Undefined, Undefined], boolnum(() => true),
|
||||
[TypeOfTypes, TypeOfTypes], boolnum((t, u) => t === u)
|
||||
)
|
||||
export const indistinguishable = [
|
||||
match([Undefined, Undefined], boolnum(() => true)),
|
||||
match([TypeOfTypes, TypeOfTypes], boolnum((t, u) => t === u))
|
||||
]
|
||||
|
|
|
@ -1,47 +1,47 @@
|
|||
import {onType} from '#core/helpers.js'
|
||||
import {match} from '#core/helpers.js'
|
||||
import {NotAType, Returns, TypeOfTypes} from '#core/Type.js'
|
||||
import {Any} from "#core/TypePatterns.js"
|
||||
import {boolnum} from "#number/helpers.js"
|
||||
|
||||
export const zero = onType(
|
||||
Any, (math, T) => {
|
||||
export const zero = [
|
||||
match(Any, (math, T) => {
|
||||
const z = math.zero(T)
|
||||
return Returns(T, () => z)
|
||||
},
|
||||
TypeOfTypes, Returns(NotAType, t => {
|
||||
}),
|
||||
match(TypeOfTypes, Returns(NotAType, t => {
|
||||
if ('zero' in t) return t.zero
|
||||
throw new RangeError(`type '${t}' has no zero element`)
|
||||
})
|
||||
)
|
||||
}))
|
||||
]
|
||||
|
||||
export const one = onType(
|
||||
Any, (math, T) => {
|
||||
export const one = [
|
||||
match(Any, (math, T) => {
|
||||
const unit = math.one(T)
|
||||
return Returns(T, () => unit)
|
||||
},
|
||||
TypeOfTypes, Returns(NotAType, t => {
|
||||
}),
|
||||
match(TypeOfTypes, Returns(NotAType, t => {
|
||||
if ('one' in t) return t.one
|
||||
throw new RangeError(
|
||||
`type '${t}' has no unit element designated as "one"`)
|
||||
})
|
||||
)
|
||||
}))
|
||||
]
|
||||
|
||||
export const hasnan = onType(
|
||||
Any, (math, T) => {
|
||||
export const hasnan = [
|
||||
match(Any, (math, T) => {
|
||||
const answer = math.hasnan(T)
|
||||
return Returns(math.typeOf(answer), () => answer)
|
||||
},
|
||||
TypeOfTypes, boolnum(t => 'nan' in t)
|
||||
)
|
||||
}),
|
||||
match(TypeOfTypes, boolnum(t => 'nan' in t))
|
||||
]
|
||||
|
||||
export const nan = onType(
|
||||
Any, (math, T) => {
|
||||
export const nan = [
|
||||
match(Any, (math, T) => {
|
||||
const notanum = math.nan(T)
|
||||
return Returns(T, () => notanum)
|
||||
},
|
||||
TypeOfTypes, Returns(NotAType, t => {
|
||||
}),
|
||||
match(TypeOfTypes, Returns(NotAType, t => {
|
||||
if ('nan' in t) return t.nan
|
||||
throw new RangeError(
|
||||
`type '${t}' has no "not a number" element`)
|
||||
})
|
||||
)
|
||||
}))
|
||||
]
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import {onType} from '#core/helpers.js'
|
||||
import {match} from '#core/helpers.js'
|
||||
import {Returns} from '#core/Type.js'
|
||||
import {Any} from '#core/TypePatterns.js'
|
||||
|
||||
export const square = onType(Any, (math, T) => {
|
||||
export const square = match(Any, (math, T) => {
|
||||
const mult = math.multiply.resolve([T, T])
|
||||
return Returns(mult.returns, a => mult(a, a))
|
||||
})
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import {ImplementationsGenerator, onType} from '#core/helpers.js'
|
||||
import {ImplementationsGenerator, match} from '#core/helpers.js'
|
||||
import {Passthru} from '#core/TypePatterns.js'
|
||||
|
||||
export const config = new ImplementationsGenerator(
|
||||
() => onType(Passthru, {relTol: 1e-12, absTol: 1e-15}))
|
||||
() => match(Passthru, {relTol: 1e-12, absTol: 1e-15}))
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import {ReturnsAs} from './helpers.js'
|
||||
import {onType} from '#core/helpers.js'
|
||||
import {match} from '#core/helpers.js'
|
||||
import {Returns} from '#core/Type.js'
|
||||
import {Any, matched} from '#core/TypePatterns.js'
|
||||
import {boolnum} from '#number/helpers.js'
|
||||
|
||||
export const equal = onType([Any, Any], (math, [T, U]) => {
|
||||
export const equal = match([Any, Any], (math, [T, U]) => {
|
||||
// Finding the correct signature of `indistinguishable` to use for
|
||||
// testing (approximate) equality is tricky, because T or U might
|
||||
// need to be converted for the sake of comparison, and some types
|
||||
|
@ -38,7 +38,7 @@ export const equal = onType([Any, Any], (math, [T, U]) => {
|
|||
// now that we have `equal` and `exceeds`, pretty much everything else should
|
||||
// be easy:
|
||||
|
||||
export const compare = onType([Any, Any], (math, [T, U]) => {
|
||||
export const compare = match([Any, Any], (math, [T, U]) => {
|
||||
const eq = math.equal.resolve([T, U])
|
||||
const gt = math.exceeds.resolve([T, U])
|
||||
const zero = math.zero(T) // asymmetry here is unfortunate, but we have
|
||||
|
@ -70,7 +70,7 @@ export const compare = onType([Any, Any], (math, [T, U]) => {
|
|||
})
|
||||
})
|
||||
|
||||
export const sign = onType(Any, (math, T) => {
|
||||
export const sign = match(Any, (math, T) => {
|
||||
const zero = math.zero(T)
|
||||
const comp = math.compare.resolve([T, T])
|
||||
return ReturnsAs(comp, t => comp(t, zero))
|
||||
|
@ -81,25 +81,25 @@ export const unequal = (math, types) => {
|
|||
return ReturnsAs(eq, (...args) => !eq(...args))
|
||||
}
|
||||
|
||||
export const larger = onType([Any, Any], (math, [T, U]) => {
|
||||
export const larger = match([Any, Any], (math, [T, U]) => {
|
||||
const eq = math.equal.resolve([T, U])
|
||||
const bigger = math.exceeds.resolve([T, U])
|
||||
return boolnum((t, u) => !eq(t, u) && bigger(t, u))(math)
|
||||
})
|
||||
|
||||
export const largerEq = onType([Any, Any], (math, [T, U]) => {
|
||||
export const largerEq = match([Any, Any], (math, [T, U]) => {
|
||||
const eq = math.equal.resolve([T, U])
|
||||
const bigger = math.exceeds.resolve([T, U])
|
||||
return ReturnsAs(bigger, (t, u) => eq(t, u) || bigger(t, u))
|
||||
})
|
||||
|
||||
export const smaller = onType([Any, Any], (math, [T, U]) => {
|
||||
export const smaller = match([Any, Any], (math, [T, U]) => {
|
||||
const eq = math.equal.resolve([T, U])
|
||||
const bigger = math.exceeds.resolve([U, T])
|
||||
return boolnum((t, u) => !eq(t, u) && bigger(u, t))(math)
|
||||
})
|
||||
|
||||
export const smallerEq = onType([Any, Any], (math, [T, U]) => {
|
||||
export const smallerEq = match([Any, Any], (math, [T, U]) => {
|
||||
const eq = math.equal.resolve([T, U])
|
||||
const bigger = math.exceeds.resolve([U, T])
|
||||
return ReturnsAs(bigger, (t, u) => eq(t, u) || bigger(u, t))
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import {ReturnsAs} from './helpers.js'
|
||||
import {onType, ResolutionError} from '#core/helpers.js'
|
||||
import {ResolutionError} from '#core/helpers.js'
|
||||
import {Returns} from '#core/Type.js'
|
||||
import {Any} from "#core/TypePatterns.js"
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import {Type} from '#core/Type.js'
|
||||
import {onType} from '#core/helpers.js'
|
||||
import {match} from '#core/helpers.js'
|
||||
import {BooleanT} from '#boolean/BooleanT.js'
|
||||
|
||||
export const NumberT = new Type(n => typeof n === 'number', {
|
||||
from: onType(BooleanT, math => math.number.resolve([BooleanT])),
|
||||
from: match(BooleanT, math => math.number.resolve([BooleanT])),
|
||||
one: 1,
|
||||
zero: 0,
|
||||
nan: NaN
|
||||
|
|
|
@ -14,9 +14,9 @@ describe('NumberT Type', () => {
|
|||
it('can convert from BooleanT to NumberT', () => {
|
||||
const convertImps = NumberT.from
|
||||
let cnvBtoN
|
||||
for (const [pattern, convFactory] of convertImps.patterns) {
|
||||
for (const {pattern, does} of convertImps) {
|
||||
if (pattern.match([BooleanT])[0] === 1) {
|
||||
cnvBtoN = convFactory(math)
|
||||
cnvBtoN = does(math)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import {NumberT} from './NumberT.js'
|
||||
|
||||
import {onType} from '#core/helpers.js'
|
||||
import {match} from '#core/helpers.js'
|
||||
import {Returns} from '#core/Type.js'
|
||||
|
||||
export const plain = f => onType(
|
||||
export const plain = f => match(
|
||||
Array(f.length).fill(NumberT), Returns(NumberT, f))
|
||||
|
||||
// Takes a behavior returning boolean, and returns a factory
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import {onType} from '#core/helpers.js'
|
||||
import {match} from '#core/helpers.js'
|
||||
import {Returns} from '#core/Type.js'
|
||||
import {Optional} from '#core/TypePatterns.js'
|
||||
import {boolnum} from './helpers.js'
|
||||
|
@ -11,7 +11,7 @@ import {NumberT} from './NumberT.js'
|
|||
|
||||
// Notice a feature of TypedDispatcher: if you specify one tolerance, you must
|
||||
// specify both.
|
||||
export const indistinguishable = onType(
|
||||
export const indistinguishable = match(
|
||||
[NumberT, NumberT, Optional([NumberT, NumberT])],
|
||||
boolnum((a, b, [tolerances = [0, 0]]) => {
|
||||
const [relTol, absTol] = tolerances
|
||||
|
@ -34,4 +34,4 @@ export const indistinguishable = onType(
|
|||
// Returns truthy if a (interpreted as completely precise) represents a
|
||||
// greater value than b (interpreted as completely precise). Note that even if
|
||||
// so, a and b might be indistinguishable() to some tolerances.
|
||||
export const exceeds = onType([NumberT, NumberT], boolnum((a, b) => a > b))
|
||||
export const exceeds = match([NumberT, NumberT], boolnum((a, b) => a > b))
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
import {plain} from './helpers.js'
|
||||
import {BooleanT} from '#boolean/BooleanT.js'
|
||||
import {match} from '#core/helpers.js'
|
||||
import {Returns} from '#core/Type.js'
|
||||
import {NumberT} from '#number/NumberT.js'
|
||||
|
||||
const num = f => Returns(NumberT, f)
|
||||
|
||||
export const number = plain(a => a)
|
||||
number.also(
|
||||
export const number = [
|
||||
plain(a => a),
|
||||
// conversions from Boolean should be consistent with one and zero:
|
||||
BooleanT, num(p => p ? NumberT.one : NumberT.zero),
|
||||
[], num(() => 0)
|
||||
)
|
||||
match(BooleanT, num(p => p ? NumberT.one : NumberT.zero)),
|
||||
match([], num(() => 0))
|
||||
]
|
||||
|
|
|
@ -2,7 +2,7 @@ import {plain, boolnum} from './helpers.js'
|
|||
import {NumberT} from './NumberT.js'
|
||||
|
||||
import {Returns} from '#core/Type.js'
|
||||
import {onType} from '#core/helpers.js'
|
||||
import {match} from '#core/helpers.js'
|
||||
|
||||
export const clone = plain(a => a)
|
||||
export const isnan = onType(NumberT, boolnum(isNaN))
|
||||
export const isnan = match(NumberT, boolnum(isNaN))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue