From f696cd554fef8e714ae0e5e88abcb19173b941ae Mon Sep 17 00:00:00 2001 From: alex Date: Tue, 25 Jan 2022 17:03:22 +0000 Subject: [PATCH] shenanigans --- js/strudel.mjs | 120 +++++++++++++++++++++++++++--------------- package-lock.json | 24 ++++----- test/pattern.test.mjs | 19 +++++++ 3 files changed, 108 insertions(+), 55 deletions(-) diff --git a/js/strudel.mjs b/js/strudel.mjs index d5803644..020eb860 100644 --- a/js/strudel.mjs +++ b/js/strudel.mjs @@ -5,6 +5,10 @@ var removeUndefineds = function(xs) { return xs.filter(x => x != undefined) } +function flatten(arr) { + return [].concat(...arr) +} + // Returns the start of the cycle. Fraction.prototype.sam = function() { return Fraction(Math.floor(this)) @@ -36,6 +40,18 @@ Fraction.prototype.gte = function(other) { return this.compare(other) >= 0 } +Fraction.prototype.max = function(other) { + return this.gt(other) ? this : other +} + +Fraction.prototype.min = function(other) { + return this.lt(other) ? this : other +} + +Fraction.prototype.show = function () { + return this.n + "/" + this.d +} + class TimeSpan { constructor(begin, end) { this.begin = Fraction(begin) @@ -71,8 +87,8 @@ class TimeSpan { intersection(other) { // Intersection of two timespans, returns None if they don't intersect. - intersect_begin = Math.max(this.begin, other.begin) - intersect_end = Math.min(this.end, other.end) + var intersect_begin = this.begin.max(other.begin) + var intersect_end = this.end.min(other.end) if (intersect_begin.gt(intersect_end)) { return(undefined) @@ -92,12 +108,12 @@ class TimeSpan { intersection_e(other) { // Like 'sect', but raises an exception if the timespans don't intersect. - result = this.intersection(other) - if (result.equals(None)) { + var result = this.intersection(other) + if (result == undefined) { // TODO - raise exception // raise ValueError(f'TimeSpan {self} and TimeSpan {other} do not intersect') } - return(result) + return result } get midpoint() { @@ -107,6 +123,10 @@ class TimeSpan { equals(other) { return this.begin.equals(other.begin) && this.end.equals(other.end) } + + show() { + return this.begin.show() + " -> " + this.end.show() + } } class Hap { @@ -158,6 +178,10 @@ class Hap { && this.value === other.value ) } + + show() { + return "(" + (this.whole == undefined ? "~" : this.whole.show()) + ", " + this.part.show() + ", " + this.value + ")" + } } class Pattern { @@ -170,7 +194,7 @@ class Pattern { // easier to express, as all events are then constrained to happen within // a cycle. var query = function(span) { - return span.spanCycles.map(subspan => this.query(subspan)).concat + return flatten(span.spanCycles.map(subspan => this.query(subspan))) } return new Pattern(query) } @@ -200,16 +224,16 @@ class Pattern { withValue(func) { // Returns a new pattern, with the function applied to the value of // each event. It has the alias 'fmap'. - return new Pattern(this.query(span).map(hap => hap.withValue(func))) + return new Pattern(span => this.query(span).map(hap => hap.withValue(func))) } // alias fmap(func) { - this.withValue(func) + return this.withValue(func) } _filterEvents(event_test) { - return new Pattern(span => this.query(span).filter(event_test)) + return new Pattern(span => this.query(span).filter(event_tespanCyclesst)) } _filterValues(self, value_test) { @@ -227,18 +251,18 @@ class Pattern { // Assumes 'this' is a pattern of functions, and given a function to // resolve wholes, applies a given pattern of values to that // pattern of functions. - pat_func = this + var pat_func = this query = function(span) { - event_funcs = pat_func.query(span) - event_vals = pat_val.query(span) + var event_funcs = pat_func.query(span) + var event_vals = pat_val.query(span) apply = function(event_func, event_val) { - s = event_func.part.intersection(event_val.part) + var s = event_func.part.intersection(event_val.part) if (s === undefined) { return undefined } return new Hap(whole_func(event_func.whole, event_val.whole), s, event_func.value(event_val.value)) } - return event_funcs.map(event_func => removeUndefineds(event_vals.map(event_val => apply(event_func, event_val)))).concat + return flatten(event_funcs.map(event_func => removeUndefineds(event_vals.map(event_val => apply(event_func, event_val))))) } return new Pattern(query) } @@ -255,43 +279,53 @@ class Pattern { } appLeft(pat_val) { - pat_func = this - var query = function(span) { - events = [] - for (event_func in pat_func.query(span)) { - event_vals = pat_val.query(event_func.part) - for (event_val in event_vals) { - new_whole = event_func.whole - new_part = event_func.part.intersection_e(event_val.part) - new_value = event_func.value(event_val.value) - events.push(new Event(new_whole, new_part, new_value)) - } - } - return events - } - return Pattern(query) - } + var pat_func = this - appRight(pat_val) { - pat_func = this var query = function(span) { - events = [] - for (event_val in pat_val.query(span)) { - event_funcs = pat_func.query(event_val.part) - for (event_func in event_funcs) { - new_whole = event_val.whole - new_part = event_func.part.intersection_e(event_val.part) - new_value = event_func.value(event_val.value) - events.push(new Event(new_whole, new_part, new_value)) + var haps = [] + for (var hap_func of pat_func.query(span)) { + var event_vals = pat_val.query(hap_func.part) + for (var hap_val of event_vals) { + var new_whole = hap_func.whole + var new_part = hap_func.part.intersection_e(hap_val.part) + var new_value = hap_func.value(hap_val.value) + var hap = new Hap(new_whole, new_part, new_value) + haps.push(hap) } } - return events + return haps } return new Pattern(query) } -// def __add__(self, other): -// return self.fmap(lambda x: lambda y: x + y).app_left(reify(other)) + appRight(pat_val) { + var pat_func = this + + var query = function(span) { + var haps = [] + for (var hap_val of pat_val.query(span)) { + var hap_funcs = pat_func.query(hap_val.part) + for (var hap_func of hap_funcs) { + var new_whole = hap_val.whole + var new_part = hap_func.part.intersection_e(hap_val.part) + var new_value = hap_func.value(hap_val.value) + var hap = new Hap(new_whole, new_part, new_value) + haps.push(hap) + } + } + return haps + } + return new Pattern(query) + } + + add(other) { + // TODO - reify other + return this.fmap(x => y => x + y).appLeft(other) + } + + get firstCycle() { + return this.query(new TimeSpan(Fraction(0), Fraction(1))) + } // def __radd__(self, other): // return self.__add__(other) diff --git a/package-lock.json b/package-lock.json index 01ba30d8..d0883aed 100644 --- a/package-lock.json +++ b/package-lock.json @@ -379,9 +379,9 @@ "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==" }, "node_modules/@sindresorhus/is": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.3.0.tgz", - "integrity": "sha512-wwOvh0eO3PiTEivGJWiZ+b946SlMSb4pe+y+Ur/4S87cwo09pYi+FWHHnbrM3W9W7cBYKDqQXcrFYjYUCOJUEQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.4.0.tgz", + "integrity": "sha512-QppPM/8l3Mawvh4rn9CNEYIU9bxpXUCRMaX9yUpvBk1nMKusLKpfXGDEKExKaPhLzcn3lzil7pR6rnJ11HgeRQ==", "engines": { "node": ">=10" }, @@ -438,9 +438,9 @@ } }, "node_modules/@types/node": { - "version": "17.0.10", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.10.tgz", - "integrity": "sha512-S/3xB4KzyFxYGCppyDt68yzBU9ysL88lSdIah4D6cptdcltc4NCPCAMc0+PCpg/lLIyC7IPvj2Z52OJWeIUkog==" + "version": "17.0.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.12.tgz", + "integrity": "sha512-4YpbAsnJXWYK/fpTVFlMIcUIho2AYCi4wg5aNPrG1ng7fn/1/RZfCIpRCiBX+12RVa34RluilnvCqD+g3KiSiA==" }, "node_modules/@types/parse-json": { "version": "4.0.0", @@ -4800,9 +4800,9 @@ } }, "@sindresorhus/is": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.3.0.tgz", - "integrity": "sha512-wwOvh0eO3PiTEivGJWiZ+b946SlMSb4pe+y+Ur/4S87cwo09pYi+FWHHnbrM3W9W7cBYKDqQXcrFYjYUCOJUEQ==" + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.4.0.tgz", + "integrity": "sha512-QppPM/8l3Mawvh4rn9CNEYIU9bxpXUCRMaX9yUpvBk1nMKusLKpfXGDEKExKaPhLzcn3lzil7pR6rnJ11HgeRQ==" }, "@szmarczak/http-timer": { "version": "4.0.6", @@ -4847,9 +4847,9 @@ } }, "@types/node": { - "version": "17.0.10", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.10.tgz", - "integrity": "sha512-S/3xB4KzyFxYGCppyDt68yzBU9ysL88lSdIah4D6cptdcltc4NCPCAMc0+PCpg/lLIyC7IPvj2Z52OJWeIUkog==" + "version": "17.0.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.12.tgz", + "integrity": "sha512-4YpbAsnJXWYK/fpTVFlMIcUIho2AYCi4wg5aNPrG1ng7fn/1/RZfCIpRCiBX+12RVa34RluilnvCqD+g3KiSiA==" }, "@types/parse-json": { "version": "4.0.0", diff --git a/test/pattern.test.mjs b/test/pattern.test.mjs index b0372f01..9ae22efe 100644 --- a/test/pattern.test.mjs +++ b/test/pattern.test.mjs @@ -15,6 +15,15 @@ describe('TimeSpan', function() { assert.equal(new TimeSpan(Fraction(0),Fraction(2)).spanCycles.length, 2) }) }) + describe('intersection_e', function () { + var a = new TimeSpan(Fraction(0), Fraction(2)) + var b = new TimeSpan(Fraction(1), Fraction(3)) + var c = new TimeSpan(Fraction(1), Fraction(2)) + var d = new TimeSpan(Fraction(1), Fraction(2)) + it('Should create an intersection', function () { + assert.equal(a.intersection_e(b).equals(c), true) + }) + }) }); describe('Hap', function() { @@ -47,4 +56,14 @@ describe('Pattern', function() { assert.equal(pure("hello").query(new TimeSpan(Fraction(0.5), Fraction(2.5))).length, 3) }) }) + describe('fmap()', function () { + it('Can add things', function () { + assert.equal(pure(3).fmap(x => x + 4).firstCycle[0].value, 7) + }) + }) + describe('add()', function () { + it('Can add things', function() { + assert.equal(pure(3).add(pure(4)).query(new TimeSpan(Fraction(0), Fraction(1)))[0].value, 7) + }) + }) }) \ No newline at end of file