Revise pattern-language wrt doubles #9

Open
opened 2024-07-14 09:19:48 +00:00 by tonyg · 2 comments
Owner

I wrote the following comment against https://gist.github.com/patternspandemic/e38d5ee5f6c1db7d62c1dfd55fa35dd7.


Oh no. Oh no. So it turns out that not only am I wrong about using objects here, but the behaviour of the pattern language is worse than I thought.

  • When constructing a LaterThan (built by schema) value, supply a number, SyndicateTimer.LaterThan(123.45). Not an object: I misremembered the interface generated by the schema compiler. Sorry.
  • When constructing a pattern over LaterThan, supply a Syndicate.Double wrapper, on asserted SyndicateTimer.LaterThan(v) where v = Syndicate.Double(123.45).
  • Things go horribly wrong if you do supply an object, with opaque messages about "invalid anyatom" being responses to undefined arising by internally uncritically treating an object as a number
  • What's also extremely galling is that you cannot at present even say on asserted SyndicateTimer.LaterThan(Syndicate.Double(123.45)), because the pattern language doesn't understand Double properly. I might be able to fix that.

So in conclusion (a) I was wrong about the code generated by my own compiler 🙄 (b) there's an egregious no-good very-bad asymmetry between constructing a double-consuming schema-produced record and constructing an analogous pattern over records and (c) there's what I think is a lacuna in the pattern language about immediate/inline Syndicate.Double patterns.

My apologies. The pattern language was the simplest thing I could think of to get off the ground and actually could use some attention. Also I appear to be relying on TypeScript too much and not doing enough dynamic checks at the correct places to make the error messages comprehensible when type errors occur in JavaScript.

I wrote the following comment against <https://gist.github.com/patternspandemic/e38d5ee5f6c1db7d62c1dfd55fa35dd7>. --- Oh no. Oh no. So it turns out that not only am I wrong about using objects here, but the behaviour of the pattern language is worse than I thought. - When constructing a `LaterThan` (built by schema) *value*, supply a *number*, `SyndicateTimer.LaterThan(123.45)`. Not an object: I misremembered the interface generated by the schema compiler. Sorry. - When constructing a *pattern over* `LaterThan`, supply a *Syndicate.Double* wrapper, `on asserted SyndicateTimer.LaterThan(v)` where `v = Syndicate.Double(123.45)`. - Things go horribly wrong if you *do* supply an object, with opaque messages about "invalid anyatom" being responses to `undefined` arising by internally uncritically treating an object as a number - What's also extremely galling is that you cannot at present even say `on asserted SyndicateTimer.LaterThan(Syndicate.Double(123.45))`, because the pattern language doesn't understand `Double` properly. I might be able to fix that. So in conclusion (a) I was wrong about the code generated by my own compiler :roll_eyes: (b) there's an egregious no-good very-bad asymmetry between constructing a double-consuming schema-produced record and constructing an analogous pattern over records and (c) there's what I think is a lacuna in the pattern language about immediate/inline `Syndicate.Double` patterns. My apologies. The pattern language was the simplest thing I could think of to get off the ground and actually could use some attention. Also I appear to be relying on TypeScript too much and not doing enough dynamic checks at the correct places to make the error messages comprehensible when type errors occur in JavaScript.
Author
Owner

Here's the state of play:

<!DOCTYPE html>

<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">

<title>2024-07-14 11:23:52 Double patterns</title>

<script src="https://cdn.jsdelivr.net/npm/@syndicate-lang/browser-stdenv@0.36.6"></script>
<script src="https://cdn.jsdelivr.net/npm/@syndicate-lang/timer@0.36.3"></script>
<!-- <script src="packages/browser-stdenv/index.js"></script> -->
<!-- <script src="packages/timer/dist/syndicate-timer.js"></script> -->

<script type="syndicate">
  // Syndicate.Dataspace.local.target.data.options.tracer = (e, a, ds, s) => s && console.log(Syndicate.stringify([e, a]));
  SyndicateTimer.boot();

  spawn named 'later than'{
    on asserted SyndicateTimer.LaterThan(1234) => {
      console.log('Later than 1234'); // ✗, even after timer 0.36.3
    }
    on asserted SyndicateTimer.LaterThan(1234.1) => {
      console.log('Later than 1234.1'); // ✓
    }
    on asserted SyndicateTimer.LaterThan(Syndicate.Double(1234.2)) => {
      console.log('Later than Syndicate.Double(1234.2)'); // ✓
    }
    on asserted SyndicateTimer.LaterThan(Syndicate.Double(1235)) => {
      console.log('Later than Syndicate.Double(1235)'); // ✓
    }

    on asserted SyndicateTimer.LaterThan(Syndicate.Double(Date.now() / 1000.0 + 5.0)) => {
      console.log("5 seconds elapsed (wrapper, inline)."); // ✓, will sporadically fail
    }

    on asserted SyndicateTimer.LaterThan(Date.now() / 1000.0 + 5.0) => {
      console.log("5 seconds elapsed (no wrapper, inline)."); // ✓, will sporadically fail
    }

    const v1 = Date.now() / 1000.0 + 5.0;
    on asserted SyndicateTimer.LaterThan(v1) => {
      console.log("5 seconds elapsed (no wrapper, variable)."); // ✓, will sporadically fail
    }

    const v2 = Date.now() / 1000.0 + 5.0;
    on asserted SyndicateTimer.LaterThan(Syndicate.Double(v2)) => {
      console.log("5 seconds elapsed (wrapper, variable)."); // ✓
    }

    const v3 = Math.floor(Date.now() / 1000.0 + 5.0);
    on asserted SyndicateTimer.LaterThan(v3) => {
      console.log("5 seconds elapsed (no wrapper, floor, variable)."); // ✗, will never trigger, even after timer 0.36.3
    }

    const v4 = Math.floor(Date.now() / 1000.0 + 5.0);
    on asserted SyndicateTimer.LaterThan(Syndicate.Double(v4)) => {
      console.log("5 seconds elapsed (wrapper, floor, variable)."); // ✓
    }
  }

  spawn named 'periodic tick (wrapper)' {
    let counter = 0;
    on message SyndicateTimer.PeriodicTick(Syndicate.Double(1.0)) => {
      console.log('tick! (wrapper)', Date.now()); // ✓
      stop on (++counter == 5);
    }
  }

  spawn named 'periodic tick (no wrapper)' {
    let counter = 0;
    on message SyndicateTimer.PeriodicTick(1.0) => {
      console.log('tick! (no wrapper)', Date.now()); // ✗, even after timer 0.36.3
      stop on (++counter == 5);
    }
  }

  spawn named 'periodic tick (outright literal)' {
    let counter = 0;
    const tick = SyndicateTimer.PeriodicTick(1.0);
    on message tick => {
      console.log('tick! (outright literal)', Date.now()); // ✗ prior to timer 0.36.3, ✓ thereafter
      stop on (++counter == 5);
    }
  }
</script>
Here's the state of play: ```html <!DOCTYPE html> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>2024-07-14 11:23:52 Double patterns</title> <script src="https://cdn.jsdelivr.net/npm/@syndicate-lang/browser-stdenv@0.36.6"></script> <script src="https://cdn.jsdelivr.net/npm/@syndicate-lang/timer@0.36.3"></script> <!-- <script src="packages/browser-stdenv/index.js"></script> --> <!-- <script src="packages/timer/dist/syndicate-timer.js"></script> --> <script type="syndicate"> // Syndicate.Dataspace.local.target.data.options.tracer = (e, a, ds, s) => s && console.log(Syndicate.stringify([e, a])); SyndicateTimer.boot(); spawn named 'later than'{ on asserted SyndicateTimer.LaterThan(1234) => { console.log('Later than 1234'); // ✗, even after timer 0.36.3 } on asserted SyndicateTimer.LaterThan(1234.1) => { console.log('Later than 1234.1'); // ✓ } on asserted SyndicateTimer.LaterThan(Syndicate.Double(1234.2)) => { console.log('Later than Syndicate.Double(1234.2)'); // ✓ } on asserted SyndicateTimer.LaterThan(Syndicate.Double(1235)) => { console.log('Later than Syndicate.Double(1235)'); // ✓ } on asserted SyndicateTimer.LaterThan(Syndicate.Double(Date.now() / 1000.0 + 5.0)) => { console.log("5 seconds elapsed (wrapper, inline)."); // ✓, will sporadically fail } on asserted SyndicateTimer.LaterThan(Date.now() / 1000.0 + 5.0) => { console.log("5 seconds elapsed (no wrapper, inline)."); // ✓, will sporadically fail } const v1 = Date.now() / 1000.0 + 5.0; on asserted SyndicateTimer.LaterThan(v1) => { console.log("5 seconds elapsed (no wrapper, variable)."); // ✓, will sporadically fail } const v2 = Date.now() / 1000.0 + 5.0; on asserted SyndicateTimer.LaterThan(Syndicate.Double(v2)) => { console.log("5 seconds elapsed (wrapper, variable)."); // ✓ } const v3 = Math.floor(Date.now() / 1000.0 + 5.0); on asserted SyndicateTimer.LaterThan(v3) => { console.log("5 seconds elapsed (no wrapper, floor, variable)."); // ✗, will never trigger, even after timer 0.36.3 } const v4 = Math.floor(Date.now() / 1000.0 + 5.0); on asserted SyndicateTimer.LaterThan(Syndicate.Double(v4)) => { console.log("5 seconds elapsed (wrapper, floor, variable)."); // ✓ } } spawn named 'periodic tick (wrapper)' { let counter = 0; on message SyndicateTimer.PeriodicTick(Syndicate.Double(1.0)) => { console.log('tick! (wrapper)', Date.now()); // ✓ stop on (++counter == 5); } } spawn named 'periodic tick (no wrapper)' { let counter = 0; on message SyndicateTimer.PeriodicTick(1.0) => { console.log('tick! (no wrapper)', Date.now()); // ✗, even after timer 0.36.3 stop on (++counter == 5); } } spawn named 'periodic tick (outright literal)' { let counter = 0; const tick = SyndicateTimer.PeriodicTick(1.0); on message tick => { console.log('tick! (outright literal)', Date.now()); // ✗ prior to timer 0.36.3, ✓ thereafter stop on (++counter == 5); } } </script> ```
Author
Owner

Situation somewhat repaired by CoerceDouble added to quasipattern, plus a few small changes to Double and float.ts generally in Preserves.

  • Now it's possible to match literal values that are either integers or doubles, receiving them as Preserves DoubleFloat instances by using CoerceDouble.

  • It's also possible to use non-integer literals in patterns: integers will stay as they are, others will be silently transparently coerced to DoubleFloat. You can then use Double to ensure consistent promotion of integers to DoubleFloat.

Situation somewhat repaired by `CoerceDouble` added to quasipattern, plus a few small changes to `Double` and `float.ts` generally in Preserves. - Now it's possible to match literal values that are either integers or doubles, receiving them as Preserves `DoubleFloat` instances by using `CoerceDouble`. - It's also possible to use non-integer literals in patterns: integers will stay as they are, others will be silently transparently coerced to `DoubleFloat`. You can then use `Double` to ensure consistent promotion of integers to `DoubleFloat`.
Sign in to join this conversation.
No Label
No Milestone
No project
No Assignees
1 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: syndicate-lang/syndicate-js#9
No description provided.