From e2136660518bc8969adbf3a48e6a7dc71d1f629b Mon Sep 17 00:00:00 2001 From: rowan Date: Sat, 5 Apr 2025 22:50:38 -0500 Subject: [PATCH] allow default interface impl --- src/algebra/index.js | 47 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 39 insertions(+), 8 deletions(-) diff --git a/src/algebra/index.js b/src/algebra/index.js index 884d3f5..c60e39b 100644 --- a/src/algebra/index.js +++ b/src/algebra/index.js @@ -1,6 +1,7 @@ import { mix } from '../mixin.js' /** @import { MixinFunction } from '../mixin.js' */ +/** @import { Fn } from './types.js' */ export const ProtectedConstructor = Symbol('ProtectedConstructor') export class ProtectedConstructorError extends Error { @@ -76,6 +77,9 @@ class Method { /** @type {MethodType} */ #type = MethodType.Instance + /** @type {Fn} */ + #implementation + /** * @param {string | Method} name */ @@ -104,6 +108,23 @@ class Method { return this } + /** @param {Fn} f */ + implementation(f) { + this.#implementation = f + return this + } + + /** + * @param {string} interfaceName + */ + _defaultImplementation(interfaceName) { + const err = new NotImplementedError( + `${interfaceName}::${this.#name}` + ) + + return function() { throw err } + } + /** * @param {Function} target */ @@ -120,13 +141,10 @@ class Method { * @param {Function} target */ implement(builder, target) { - const err = new NotImplementedError( - `${builder.name}::${this.#name}` - ) - this._getInstallationPoint(target)[this.#name] = function() { - throw err - } + const impl = this.#implementation || this._defaultImplementation(builder.name) + + this._getInstallationPoint(target)[this.#name] = impl } } @@ -196,7 +214,15 @@ class Interface { } } -class BaseSet { } +/** @template T*/ +class BaseSet { + _value + + /** @param {T} value */ + constructor(value) { + this._value = value + } +} /** * @param {PropertyKey} key @@ -301,7 +327,12 @@ export const Traversable = new Interface('Traversable') export const Chain = new Interface('Chain') .extends(Apply) - .specifies('chain') + .specifies( + Method.from('chain') + .implementation(function(f) { + return f(this._value) + })) + ) export const ChainRef = new Interface('ChainRec') .extends(Chain)